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
  • API keys and workspaces/docs/authentication
  • 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, scenes and stickers/docs/generate/design-assets
  • Cursor follower/docs/generate/cursor-follower
  • Batch generation/docs/generate/batch
  • 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
  • Play a mascot in your app/docs/integrations/playback
  • Hosting and file formats/docs/generate/cdn
  • File sizes/docs/generate/file-sizes
  • Image and video exports/docs/manage/media-exports
  • Terminal quickstart/docs/terminal
  • Command line reference/docs/terminal/commands
  • CLI browser login/docs/authentication/cli
  • Float a mascot on your Mac/docs/integrations/desktop
  • TypeScript SDK/docs/sdk/typescript
  • 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
  • Changelog/docs/reference/changelog
  • Migrate to mascots and canvases/docs/manage/studio-migration
Get an API key
Documentation

Changelog

Changes to the Masko API are recorded here, newest first. Breaking changes are flagged clearly with a migration note.

Read the notes for any version that is newer than when you last integrated, then update your REST client against the current OpenAPI specification.


Size variant backfills add only missing files, AV1 included (October 27, 2026, behavior change)

POST /v1/mascots/{id}/size-variants with {} now makes every file an animation lacks, format by format: WebM, HEVC, stacked MP4 and stacked AV1, at the animation's own width and at each size. Before, it skipped a size once its WebM and HEVC files existed, so animations made before AV1 never got their AV1 files. Files that exist are never remade and keep their links. force: true still remakes every sized file.

Send feedback to the Masko team (October 27, 2026, additive)

POST /v1/feedback and the MCP tool send_feedback send feedback to the Masko team about a Masko feature, the MCP server, the REST API or the docs. Only summary is required; feedback_type, sentiment, friction_points, suggested_improvement, details, task_completed, resource_id and agent are optional. Read-only keys and connections can send it. Each account can send 5 a minute and 30 a day; more returns 429 rate_limited. The MCP server now also sends instructions to every app that connects, telling agents when to use it. See send feedback to Masko.

File sizes in job results, assets and webhooks (October 27, 2026, additive)

GET /v1/jobs/{id} and the job.completed webhook add file_sizes: each file's size in bytes, under the same key as its link in urls, or null when the file cannot be read. Every asset (GET /v1/assets, GET /v1/mascots/{id}/assets, GET /v1/assets/{id}) adds file_size, in bytes once the file is completed. It gives a quick idea of what a mascot weighs before you download anything.

AV1 files for app players (October 27, 2026, additive)

Every animation made from now on also gets a stacked AV1 file (stacked_video_av1): colour above, transparency below, like the stacked MP4, two to three times lighter than HEVC or the stacked MP4 at the same look. GET /v1/canvases/{canvasId}/releases/{releaseId}/delivery takes formats=av1: with target=apple or target=android, each clip that has the file comes as videos.av1 in place of hevc or stacked. Without formats, and with other targets, deliveries are unchanged. Masko player 0.1.6 plays it on Apple devices (with the device's AV1 chip or dav1d inside the player) and on Android phones with an AV1 decoder, and gives the value to send as MaskoPlayer.formats; React Native gets it as maskoFormats() in 0.1.7. The CDN export lists the file as transparent_video_av1. Animations made earlier keep their files.

The Masko player plays clips' own voices by default (October 26, 2026, behavior change)

Masko player 0.1.3 plays a clip's own voice (hasAudio) unless your app turns sound off: sound is now on by default, and sound: false (setSound(false) on the web) mutes it. Browsers allow sound only after the person's first click or key press on the page; until then the player plays muted, and the voice is heard from the next clip or loop. One animation played with clip plays its file's own voice too. To keep 0.1.2's silence, pass sound: false.

The Masko player plays one animation from its files (October 25, 2026, additive)

Masko player 0.1.2 plays one looping animation without a canvas: give it the animation's hosted files in place of a delivery, clip: { webm, hevc } on the web and in React, MaskoPlayer(clip:) with the HEVC file on Apple, loadClip with the stacked MP4 on Android, and clip: { hevc, stacked } in React Native. It plays the file each platform shows with transparency and loops it. See play one animation. Releases play as before.

Release ids and clip voices in deliveries (October 25, 2026, additive)

GET /v1/canvases/{canvasId}/releases/{releaseId}/delivery and GET /v1/canvases/{canvasId}/export?delivery=1 write release.id, a fingerprint of the canvas that plays, without its links: a fresh delivery with the same id only renews the links. A clip with its own voice carries hasAudio: true, so a player with sound on unmutes it; a release compiled earlier gets it the next time its mascot version is compiled. Empty condition groups and sounds without a link are left out, and manifest size variants list only the formats of the requested target. Players of contract 1 need no change.

Turn on hosting with the API (October 23, 2026, documentation)

POST /v1/mascots/{id}/publish is now in the OpenAPI specification and the docs: it turns on asset hosting, the same switch as Get Links in Studio, so a mascot made in Studio or through the MCP server gets permanent public links. See turn on hosting. The call itself is unchanged. The 409 cdn_export_not_ready message from GET /v1/mascots/{id}/cdn-export now says whether hosting is off or no file is hosted yet, and names this call. The status, code and details are unchanged.

.mkpk exports for ESP32 boards (October 23, 2026, additive)

POST /v1/assets/{id}/exports accepts format: "mkpk": one animation as a .mkpk pack, the format the ESP32 Masko SDK plays. size is required and is the exact frame width, a multiple of 16 from 32 to 1024. The new optional mkpk object sets screen_width and screen_height (together; the frames are centred on that screen), fps (default 24), quality (default 75) and background_color (default #000000). Export receipts for this format include the complete settings under mkpk. Mascot settings accept publish_params.mkpk_exports to give every future forward animation one pack with the same settings. Existing formats and fields are unchanged.

Release delivery for players (October 23, 2026, additive)

GET /v1/canvases/{canvasId}/releases/{releaseId}/delivery and GET /v1/canvases/{canvasId}/export?delivery=1 accept target=apple, which returns only the HEVC links an iPhone, iPad or Mac app plays, and target=android, which returns only the stacked MP4 links (colour above, transparency below) an Android app plays. Releases made from now on carry the stacked files; an Android delivery of an older release has no clip links, so release the canvas again. An edge can set speedInput, the name of a number input its clip speed follows (speed times the value the app sets, kept between 0.2 and 4), through PATCH /v1/canvases/{canvasId}/edges/{edgeId}; releases carry it. Every delivery now carries playerContract (the version of the playback rules, 1) and requires (the graph features it uses: any-state, condition-groups). A player refuses a delivery whose playerContract it does not know or whose requires names a feature it does not implement. Existing targets and fields are unchanged. The JSON Schema describes the whole envelope.

Silent Standard animations (October 21, 2026)

Standard animations no longer carry a soundtrack. The video model invented one for every clip, so the video, WebM, HEVC and stacked files played sounds nobody asked for. New animations have no audio track, and every picture frame is unchanged. Talking animations keep their voice. Animations made before this date keep their sound.

Applications removed (October 21, 2026, breaking)

GET /v1/applications, POST /v1/applications, GET /v1/applications/{id} and POST /v1/applications/{id}/keys are removed and return 404. Application secret keys (masko_sk_) have had no endpoint that accepts them since playback sessions were removed on September 27, 2026, and no account served a mascot through one.

Migration: call the REST API from your backend with an API key, and connect AI apps through the MCP server. Your app plays exported files or hosted links and needs no Masko credential.

Shorter Standard animations (October 18, 2026, additive)

Under API version 2026-09-26, animation_model: "standard" accepts 2 to 15 whole seconds instead of 5 to 15, still at 2 credits per second, so a 3 second animation costs 6 credits. Requests that worked before are unchanged.

Voices for every account (October 10, 2026)

Under API version 2026-09-26, every account can add a voice. The voice calls (suggestions, adjust, samples and keeping a voice with PUT) no longer return 403 with details.reason: "voice_locked"; request and response shapes are unchanged.

Mascots from a brand book (October 9, 2026, additive)

Under API version 2026-09-26.

  • New POST /v1/mascots/from-brand-book: send a brand book as public links (a PDF up to 50 MB, or page images) or uploads, at most 30 pages, and one job reads it for free, draws every mascot view and prop for 1 credit each (at most 17), and creates the mascot with its references, description, colors, style, don'ts and props. Optional max_credits caps the spend. Nothing is charged when the brand book has no mascot, costs more than the cap, or the balance is short.
  • Jobs of type mascot_brand_book report step while running and result with mascot_id once completed.
  • POST /v1/upload accepts JSON { "content_type": "application/pdf", "size": BYTES } and returns a signed upload_url to PUT a PDF of up to 50 MB straight to storage. The returned asset_id works in files of POST /v1/mascots/from-brand-book.

Talking animation price reduction (October 6, 2026)

Under API version 2026-09-26, talking animations cost 2 credits per second instead of 3. One minute costs 120 credits. Estimates and refunds use the reduced rate; request and response shapes are unchanged.

Talking animations up to 5 minutes (additive)

Under API version 2026-09-26.

  • A talking animation now holds a talk of up to 5 minutes of video, instead of 2 minutes. A talk longer than 5 minutes returns 400.
  • speech.script accepts up to 15,000 characters and speech.text up to 7,500.

Talking animations up to 2 minutes (additive)

Under API version 2026-09-26.

  • A talking animation now holds a talk of up to 2 minutes of video, instead of about 14 seconds of speech. A talk longer than 15 seconds is recorded in one go and cut in its real pauses into takes that start and end on the start image, then joined into one video. The voice stays as recorded; the video model can lengthen the pause at a cut by a fraction of a second, and the transcript's times include it.
  • speech.script accepts up to 6,000 characters and speech.text up to 3,000. A talk longer than 2 minutes returns 400.
  • Movements are performed in place: a move toward the viewer, such as leaning in close, no longer changes the framing, and spoken words are never drawn on screen.

Talking animations (additive)

Under API version 2026-09-26. Adding a voice unlocks once the account has spent $50 on Masko; until then the voice design calls return 403 with details.reason: "voice_locked".

  • POST /v1/mascots/{id}/generate accepts speech with type: "animation": the mascot says a line in its voice, with movements written in square brackets. Costs 3 credits per second; the request charges the longest the line could need and refunds unused seconds once the voice is recorded. dry_run: true returns the estimate for free. The receipt adds estimate, script, and audio and transcript asset IDs.
  • New voice endpoints under /v1/mascots/{id}/voice and /v1/mascots/{id}/variants/{variantId}/voice: get, keep (PUT), remove, suggestions, adjust, and samples (1 credit for three).
  • New asset types audio (MP3) and transcript (JSON). Video metadata of talking animations reports has_audio: true.

See talking animations.

Generation response privacy

Public job and asset responses now omit internal generation execution details for all API versions and credentials. Customer-authored mascot descriptions, styles, references, requested edits and public generation tiers remain available. Stored generation records are unchanged.

Migration: remove the former include=prompts query option; it no longer changes the response. Do not depend on raw execution fields in job input_data, output_data or asset metadata. Mask-refinement quality is now returned as original or pro; older input values are still accepted. Use job IDs and request IDs when contacting support about failures.

Direct image animation

Available in the production OpenAPI specification as of September 28, 2026, under API version 2026-09-26.

  • New POST /v1/animations animates an uploaded image under an existing mascot_id, or explicitly creates a mascot via create_mascot: {project_id, name?} in the same request. An omitted mascot name is supplied by AI; no character description is generated. Returns the mascot ID for reuse alongside the job receipt. Defaults to Standard, 5 seconds, 10 credits. Supports Idempotency-Key across mascot creation and generation.

  • Input-framing behavior change: existing horizontal and vertical image sources are now center-cropped to square before animation, including item-only sources and transition end frames. Previously the full image reached the video model and only the resulting animation was cropped. Square inputs are unchanged. Originals remain intact and cropping adds no credits. To retain a specific framing, upload a prepared square image or set the new source_image_crop / end_image_crop pixel rectangles. See image framing.

  • Animate an unattached image from /v1/upload directly under an existing mascot, without generating another pose or changing mascot references. The source import preserves the original file and selected variant context. Only animation credits are charged.

How versions work

The API path stays /v1. Each set of changes is named by a date, and the current version is 2026-09-26. Send it as the Masko-API-Version header (or api_version query parameter); every response returns the version it used in the same header. Additive changes, such as new fields, endpoints or optional headers, ship inside the current version. A change that could break a working client gets a new date and a migration note here. The OpenAPI specification's info.version always equals the current version.

Media exports (additive)

Available in the production OpenAPI specification as of September 28, 2026, under API version 2026-09-26.

  • New POST/GET /v1/assets/{id}/exports create and list image/video exports, with reusable jobs, signed downloads, resizing and optional regeneration.
  • Mascot settings add publish_params.image_exports for PNG/WebP versions and sizes. New POST /v1/mascots/{id}/exports explicitly backfills saved settings.
  • POST /v1/projects/{id}/export-settings applies settings to current project/folder mascots, with optional backfill. Existing video routes and settings remain compatible.
  • Image exports preserve source files, transparency and aspect ratio, without upscaling or generation credits. See media exports.

2026-09-26

Deployed on 2026-09-27. The API contract date remains 2026-09-26.

Mascots and canvases

  • Canonical routes /v1/mascots and /v1/canvases return mascot_id. Existing /v1/collections routes keep working with their legacy fields and are marked deprecated. See the migration guide.
  • New GET /v1/canvases/{canvasId}/status: generation progress with generation (ready plus node and edge counts), preview, variants, failed_nodes and failed_edges.
  • Canvas responses contain only public fields: object, id, project_id, mascot_id, name, graph, graph_content_hash, created_at, updated_at.
  • GET /v1/canvases pages like other lists when you send limit, offset or cursor, and returns 400 with param: "project_id" when project_id is missing.
  • generate-all returns poll_url on each job, and 409 appearance_unavailable when a mascot has no published appearance to generate with.
  • Breaking in this version: the hosted character registry and its plans, runs, versions and playback issuer are retired. Existing credentials and installed releases are preserved. See terminal setup.

Conventions (additive)

  • Every response has a Request-Id header and the Masko-API-Version it used.
  • Errors add doc_url, request_id and, when a field is at fault, param. Validation errors list every problem in details.issues. Existing code values are unchanged. See error codes.
  • Standard authenticated resource POST endpoints accept Idempotency-Key (/v1/auth/* and /v1/admin/* are excluded). Completed results, including 500 errors, replay for 24 hours with the same workspace, API version and exact request bytes. See conventions.
  • Lists return meta.pagination.next_cursor; pass it back as cursor. offset keeps working.
  • Resources carry an object field naming their type, for example "object": "mascot" or "object": "job".
  • Error messages on mascot routes say "Mascot not found" instead of "Collection not found". The not_found code is unchanged.

Retry fixes

  • Both canonical and legacy collection canvas DELETE return 409 conflict when checkpoints or releases retain history. Generated assets remain stored.
  • Canonical canvas operations accept idempotency keys through their nested handlers without rejecting their own reservation.
  • Replays recheck resource access and preserve the original API representation. A key cannot retrieve a response from another credential workspace or API version.
  • Multipart uploads preserve binary bytes. Reusing an expired completed key no longer fails on a consumed body, and concurrent retries cannot remove a replacement reservation.
  • Errors after execution retain their keys, preventing a retry from repeating committed writes. If the receipt cannot be saved, the API returns 503 idempotency_persistence_failed and keeps the reservation blocked. Retry with the same key and check the operation outcome before starting another request.

Jobs

  • GET /v1/jobs/{id} and GET /v1/jobs initially omitted internal execution details by default. The generation response privacy change above makes that omission unconditional. Customer-authored mascot prompts, styles, references, variants and transition endpoints remain available.

Webhooks (additive)

  • Deliveries add id (stable across retries) and object: "event", plus Masko-Event-Id and a timestamp-bound Masko-Signature: t=...,v1=... header next to the existing signature headers.
  • Failed deliveries retry for about 21 hours with increasing delays. A webhook is disabled after 100 consecutive failures. Deleting a webhook also deletes its delivery history. See webhooks.

Marketplace listings

  • Organization mascots publish under a team profile with a shared handle, name, logo and bio. Team owners/admins manage publishing, existing creator eligibility and review still apply, and earnings go to the team wallet. Publication state now includes the seller workspace and management permission.

  • Marketplace purchases can belong to Personal or the selected organization. Organization purchases spend team credits and are shared with current team members inside that workspace. Personal purchases stay personal. Library API reads and canvas creation require a license in the credential/project workspace.

  • Publication supports withdraw, returns listing_preview and sales to the owner, makes the description optional, and requires at least 5 finished animations and a creator handle before submitting.

  • Studio Marketplace prices and purchase amounts use credits from your existing balance. The catalog returns price_credits. Existing purchases and ownership remain unchanged; older Desktop versions retain their compatible price fields.

1.14.0 - 2026-08-20

Added

  • GET /v1/collections/:id/canvases/:canvasId now returns status.nodes.failed and status.failed_nodes. Failed node and edge entries include the related job ID and a customer-safe error message.

Compatibility

  • status.nodes.pending still counts all incomplete nodes, including failed nodes. Existing polling clients keep their previous behavior and can adopt status.nodes.failed when ready.

1.6.0 - 2026-05-23

Added

  • GET /v1/collections/:id/cdn-export returns the same published CDN JSON shape as the collection page Get Links export modal. Use this for copy-paste app manifests; use /items and /assets for raw IDs, prompts, metadata, and status checks.

Changed

  • CDN export requests now fail clearly with 409 cdn_export_not_ready when asset hosting is disabled, the collection is not published, or no CDN assets have been published yet.

1.5.0 - 2026-05-16

Added

  • GET /v1/assets and GET /v1/collections/:id/assets now accept optional include_file_urls=false for faster metadata-only lists. Defaults are unchanged, so existing callers still receive signed file_url values.

1.2.0 - 2026-04-19

API cleanup pass. Applies one consistent convention across every endpoint: plural resources, verb endpoints only for one-shot actions, {data, meta?} response envelope, generation responses with data.poll_url, and path-parameter IDs instead of bodies.

Added

  • POST /v1/analyze - unified analysis endpoint. Body: {type: "image" | "url", image_url?, url?}. Replaces the two legacy endpoints.
  • GET /v1/collections/:id/suggestions - AI-suggested action names for a mascot collection. Read-only, no credits.
  • GET /v1/assets and GET /v1/assets/:id - first-class access to assets. Filter by collection_id, type, is_archived.
  • DELETE /v1/assets/:id - archive an asset (soft delete).
  • PATCH /v1/collections/:id/items/:itemId - update an item's name or prompt.
  • DELETE /v1/collections/:id/items/:itemId - archive an item.
  • DELETE /v1/collections/:id/canvases/:canvasId - delete a canvas.
  • PATCH /v1/canvas-templates/:id and GET /v1/canvas-templates/:id.
  • DELETE /v1/collections/:id/references/:assetId - remove a reference by path param.

Changed (breaking)

  • POST /v1/collections/:id/generate-batch - returns 202 Accepted with data.jobs, data.total_cost, and data.poll_url.
  • DELETE /v1/collections/:id/references - the asset ID moves from the body to the URL path. Old: DELETE /references with {asset_id} in body. New: DELETE /references/:assetId.
  • POST /v1/collections/:id/canvases - now accepts an optional template_id (plus node_overrides, edge_overrides). The legacy /canvases/:canvasId/from-template endpoint is removed - apply templates at creation time instead.
  • PUT /v1/collections/:id/canvases/:canvasId - now PATCH /v1/collections/:id/canvases/:canvasId. Body unchanged.
  • GET /v1/collections/:id/canvases/:canvasId/status - removed. The status object is now on the canvas GET response.
  • PATCH /v1/collections/:id/cdn-slug - removed. Set slug via PATCH /v1/collections/:id with {slug} in the body.
  • GET /v1/collections/:id/cdn-status - removed. The cdn_status array is now on GET /v1/collections/:id.
  • GET /v1/collections/:id/urls - removed. Use GET /v1/collections/:id/assets - URLs are already attached to each asset.
  • Paginated responses - pagination now lives under meta.pagination instead of top-level pagination. Shape is unchanged: {total, limit, offset, has_more}.
  • Async responses - poll_url now lives inside data (previously top-level). Clients that construct the poll URL from job_id are unaffected.

Removed

  • POST /v1/analyze-image - use POST /v1/analyze with {type: "image", image_url}.
  • POST /v1/analyze-url - use POST /v1/analyze with {type: "url", url}.
  • POST /v1/collections/:id/suggest-actions - use GET /v1/collections/:id/suggestions.

Not changed

  • POST /v1/collections/:id/generate - URL, body, and response are unchanged.
  • POST /v1/upload - unchanged.
  • GET /v1/jobs/:id - unchanged. Still supports ?wait=true&timeout=120.
  • Authentication and credit costs - all unchanged.

Migration checklist

  • POST /analyze-image callers: swap to POST /analyze with {type: "image", image_url}.
  • POST /analyze-url callers: swap to POST /analyze with {type: "url", url}.
  • POST /suggest-actions callers: swap to GET /suggestions. No body needed.
  • DELETE /references body callers: move asset_id from body to URL path.
  • cdn-slug / cdn-status / urls callers: read and write via the main collection endpoints.
  • Canvas from-template callers: pass template_id on POST /canvases instead.
  • Canvas PUT callers: change the method to PATCH.

Most customers will not need code changes if they only use POST /generate and GET /jobs/:id with the documented request and response shapes.


1.1.0 - 2026-04-10

  • Envelope enforcement: every v1 response now wraps data in {data} or {error: {code, message}}. Lists include pagination metadata.
  • Introduced the api-key permission levels: read, write, admin. New keys default to write.

1.0.0 - 2025-12-01

Initial public release of the Masko v1 API covering projects, collections, items, canvases, generation, jobs, webhooks, and credits.


How to follow updates