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

Canvases and releases

A canvas is the state machine behind an interactive mascot: nodes are poses, and edges are the animated transitions between them with the conditions that trigger them. A canvas belongs to a project and can mix Original and variant poses in one graph.

Create a canvas

Creating an empty draft generates no media. The mascot sets the starting identity and the project controls access.

curl -X POST https://api.masko.ai/v1/canvases \
  -H "Authorization: Bearer $MASKO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"project_id":"PROJECT_ID","mascot_id":"MASCOT_ID","name":"Main Canvas"}'

The response has data.id, data.graph and data.graph_content_hash. Optional variant_id sets the default identity for new poses.

curl 'https://api.masko.ai/v1/canvases?project_id=PROJECT_ID' \
  -H "Authorization: Bearer $MASKO_API_KEY"

Edit safely

Read the draft, edit the complete graph and send its revision as expected_graph_hash. A concurrent edit returns 409, so read again before reapplying your change.

const base = 'https://api.masko.ai/v1';
const headers = { Authorization: `Bearer ${process.env.MASKO_API_KEY}` };
const read = await fetch(`${base}/canvases/${canvasId}`, { headers });
const result = await read.json();
if (!read.ok) throw new Error(result.error.message);
const draft = result.data;
const graph = structuredClone(draft.graph);
// Edit graph.nodes, graph.edges and graph.inputs here.
const saved = await fetch(`${base}/canvases/${canvasId}`, {
  method: 'PATCH',
  headers: { ...headers, 'Content-Type': 'application/json' },
  body: JSON.stringify({ graph, expected_graph_hash: draft.graph_content_hash })
});
const receipt = await saved.json();
if (!saved.ok) throw new Error(receipt.error.message);

Graph fields are in Build a canvas.

Generate and validate

Dry-run POST /v1/canvases/CANVAS_ID/generate-all to review the work and cost, then submit the same selection with approved_plan_id and expected_graph_hash. Track it with GET /v1/canvases/CANVAS_ID/status instead of resubmitting; see canvas generation. Validation and history reads are free.

Checkpoints and releases

{
  "action": "checkpoint",
  "name": "Before adding a transition",
  "expected_graph_hash": "CURRENT_GRAPH_HASH"
}

GET /v1/canvases/CANVAS_ID/history returns the draft, checkpoints and releases. POST one action to the same route:

ActionAdditional fields
checkpointname, expected_graph_hash
restorecheckpoint_id, expected_graph_hash
releaseoperation_id (UUID), notes, expected_graph_hash
restore_releaserelease_id, expected_graph_hash
copy_releaserelease_id, name, expected_graph_hash
  • Checkpoints can hold unfinished work. A release freezes a complete, playable graph with its exact dependencies, so it needs complete media and a fresh UUID operation_id; notes is optional.
  • A release the Masko player would not play is refused with 422 and the reasons: a condition it cannot read (an unknown comparison, a value that is not true, false or a number), an input without a type or starting value, a move to a pose that is not in the canvas, a speed of 0, or a pose without a picture.
  • Restore saves the current work in a checkpoint first.
  • No action regenerates media, spends credits, publishes content or activates a mascot on a Mac. An installed release stays pinned until explicitly replaced.

Deliver a release

Your backend fetches the release's delivery with your API key and your app plays it with the Masko player, which runs every canvas rule: Play a canvas has the backend route, the targets and the set and fire calls. target=desktop returns the full media set, for Masko for Mac. The delivery holds temporary signed playback links, not a credential. Never put an API key in a website or a shipped app.

Templates and export

To start from a ready-made graph, save a canvas template into an empty draft. Export reads an editable graph with delivery URLs; use a release when playback must keep exact media.