MCP tools
59 tools. A session lists only the 10 core ones; the rest load with find_tools / load_tools, or run through edit {op: "
add_motion_template: Add a template to a frame (familytemplates)apply_effects: Apply image effects (familyeffects)ask_motion_agent: Ask the frame editor agent (familyalias)cancel_node_loop: Cancel a queued loop or variant batch (familygeneration)canvas_file: Save a canvas to a .feega file, or import one (familycanvas)canvas_tool: Work a project canvas (familylegacy)delete_row: Delete rows (familydata)describe: (listed)describe_node_types: Node data shapes (familydata)edit: Edit the canvas and its frames (listed)edit_storyboard_card: Rewrite a storyboard card (familystoryboard)enhance_prompt: Rewrite a prompt for the model that will render it (familygeneration)find_tools: (listed)forget_app_account: Forget the test app account (familyteam)get_app_account: Show the test app account (familyteam)get_media: See a node’s media (familygeneration)get_motion_embed: Read a frame web embed (familymotion)get_motion_run: Read a frame agent run (familymotion)get_motion_summary: Read a frame (familymotion)get_render: Read a render (listed)get_storyboard: Read the storyboard of a frame (familystoryboard)insert_row: Insert a row (familydata)list_effects: List image effects (familyeffects)list_layouts: List custom layouts (familylayouts)list_motion_revisions: List the saved versions of a frame (familymotion)list_motion_templates: List frame templates (familytemplates)list_motion_videos: List frames (familymotion)list_orgs: List organisations (listed)list_shader_effects: List shader effects (familymotion)list_team: List an organisation team (familyteam)load_tools: (listed)make_effects_pair: Make a shape cutout A/B pair (familyeffects)model_allowlist: Read or set the models an org allows (familyteam)motion_budget: Read or raise the budget of a frame (familymotion)motion_editor_op: Run a frame editor action (familylegacy)motion_tool: Run a frame editor tool (familylegacy)new_motion_from_template: Start a frame from a template (familytemplates)patch_effect: Patch a custom effect (familyeffects)patch_layout: Patch a custom layout (familylayouts)preview_node_loop: Preview a node’s loop (familygeneration)publish_motion_embed: Publish a frame as a web embed (familymotion)publish_to_gallery: Publish a video to the gallery (familygallery)query: Query the database (listed)remix_gallery_item: Remix a gallery item (familygallery)render_video: Render a frame (listed)restore_motion_revision: Restore a saved version of a frame (familymotion)run_node_generation: Generate a node’s content (familygeneration)run_node_loop: Queue a generation node loop (familygeneration)search_gallery: Search the remix gallery (familygallery)share_motion_frame: Share one frame as a link (familymotion)spend_caps: Read or set the spend caps of an org (familyteam)team_op: Change organisations and teams (familyteam)unload_tools: (listed)update_row: Update rows (familydata)view: See the canvas (listed)view_motion_frames: See still images of a frame (familymotion)write_effect: Write a custom effect (familyeffects)write_layout: Write a custom layout (familylayouts)write_storyboard: Write the storyboard of a frame (familystoryboard)
add_motion_template
Section titled “add_motion_template”Insert an editable copy of a template (id from list_motion_templates) at at seconds, its fields set from vars (keys and types as listed). sound (default true) lays its key taps and clicks on the SFX track. Saved as a new revision; no AI, free.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
node_id | string | yes | |
id | string | yes | |
at | number | ||
vars | object | ||
sound | boolean |
apply_effects
Section titled “apply_effects”Applies one effect or a chain (list_effects) and lands the result as a new asset — the same render the canvas Effects editor does. On an image node it creates an effects node beside it, wired to it; on an effects node it replaces the stack with effects when given, otherwise re-renders the stack it has. effects: [{ id, params?, enabled? }] in order, missing params take their defaults. Returns { node_id, asset_id }. Spends no credits: no AI provider is called.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
node_id | string | yes | |
effects | array of object |
ask_motion_agent
Section titled “ask_motion_agent”Edit a motion video (a motion canvas node) by asking the motion editor’s own AI in plain words, e.g. “make the title red and add a bounce”. It runs one turn of the same agent as the editor chat, with its own tools, writes a new revision of the video and posts the exchange in the editor chat. Find the node id with list_motion_videos; read the video first with get_motion_summary to name clips precisely. Returns at once with a run_id (running): poll get_motion_run every few seconds until done, which carries the reply, the summary and the new revision version. wait: true polls for you, up to about 4 minutes of a turn that can run up to 30. The agent looks at its own frames even with no editor open. Spends credits. attachments (up to 10): images (PNG, JPG, WebP, GIF) the agent sees and can place in the video, and PDF/DOCX/PPTX/XLSX/CSV/TXT/MD/HTML files it reads as text — each one a public url, an asset_id of the project, or inline base64 data with name and mime_type; at most 20 MB each. When the agent wants the user’s taste it ends its turn with reference_pick in the run (question and candidate pictures with ids): show them to the user, then call again with reference_pick: { follow: [ids], avoid: [ids], note } (prompt optional), or { follow: [], avoid: [], rejected: true, query, avoid_all } when none fit: the agent searches again. Followed pictures become the targets, avoided ones what not to do.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
node_id | string | yes | |
prompt | string | ||
wait | boolean | ||
attachments | array of object / object / object | ||
reference_pick | object |
cancel_node_loop
Section titled “cancel_node_loop”Stops the combinations still queued for this node — the ones a tick has already claimed finish regardless, and anything already produced stays in the output list. It also stops the runs still pending of a run_node_generation variant batch started from this node. Returns how many runs it actually stopped.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
node_id | string | yes |
canvas_file
Section titled “canvas_file”A canvas as a local .feega file, to carry work from a local feega to feega.app. save {project_id, canvas_id, path}: writes it (path = file or folder). import {project_id, path}: opens it as a new canvas. Free.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | ||
action | save / import | yes | |
project_id | string | yes | |
canvas_id | string | The canvas to save; required for save. | |
path | string | yes | Where to write the file (save) or the file to read (import). |
canvas_tool
Section titled “canvas_tool”Deprecated, use edit. The canvas ops of the project chat, on one project (project_id), with input in camelCase. First call op “describe” with {} for every op with one line, or {op} for its strict JSON input schema. Frames and stills: draw_frame, then edit inside with motion_tool. Reads: list_canvases {}, estimate_text_cost {canvasId,nodeId,prompt?,model?} (token estimate of a text run), suggest_next_steps {canvasId,nodeId}, list_nodes {canvasId}, canvas_snapshot {canvasId} (nodes, connections, runs, products, socialPosts, influencers, revision), canvas_revision {canvasId} (live revision, or canvas/project gone), list_runs {nodeId}, list_models {medium} (models this project can run: provider, credits, uncensored, and routes[] — one per provider that serves it, for run_node provider), preview_node_loop {nodeId}, preview_run_graph {graph:“downstream”,nodeId} | {graph:“stale”,canvasId,nodeIds?} (ordered steps + credits: quote before run_graph). Writes, free: create_node {canvasId,type,x,y,displayName?,data?} (data per describe_node_types), update_node {nodeId,data} (only changed fields, null removes), move_node {nodeId,x,y,z?}, resize_node {nodeId,width,height}, rename_node {nodeId,name} (empty = default name), set_node_color {nodeId,color: red|orange|yellow|green|blue|purple|grey|null}, connect_nodes {canvasId,sourceNodeId,targetNodeId,sourceHandle?,targetHandle?} (a frame takes no inputs: use place_in_frame), delete_node {nodeId} (soft, drops its lines), cancel_node_loop {nodeId}, cancel_run {nodeId} (stop one running generation), duplicate_nodes {canvasId,nodeIds}, layers_to_frame {nodeId} (a split image into a frame of image elements), write_nodes {canvasId,items:[{node_id,version,patch}]} (merge each patch, per-node written|conflict|not_found), paste_nodes {canvasId,nodes:[{type,data,x,y}],edges?:[{sourceIndex,targetIndex,sourceHandle?,targetHandle?}]}, list_connections {canvasId}, disconnect_nodes {connectionId}, set_edge_mode {connectionId,mode:fixed|iterate}, undo_gesture {canvasId,items} (replay a recorded gesture inverse; refused when the canvas moved on), run_demo {canvasId} (first-run example chain), end_onboarding {status:dismissed|completed}, create_canvas {}, rename_canvas {canvasId,name}, delete_canvas {canvasId}, rename_project {name}, share_canvas {canvasId,on} (view-only link), share_doc {nodeId,on}, list_templates {}, insert_template {canvasId,templateId,x,y}, list_techniques {} (saved flows of the workspace with their input and output slots), save_technique {canvasId,nodeIds,name} (package a connected selection, 2+ nodes, as a reusable technique), place_technique {canvasId,techniqueId,x,y} (a live node that references the technique: editing the technique updates it), run_technique_node {nodeId} (runs the saved graph of the technique with the texts wired into the node; spends credits), detach_technique {canvasId,nodeId} (swaps the node for a copy of the graph), open_technique {techniqueId} (writes the graph on its own canvas to edit; save_technique with the same name bumps the version), run_technique {canvasId,techniqueId,x,y,inputs?:[{node,value}],run?} (places a copy of the flow, sets the prompt of each input slot, runs the inner graph; run:false only places it), delete_technique {techniqueId}, add_frame_from_template {canvasId,templateId,format?,values?,x,y}, move_frame_element {frameId,elementId,toFrameId?,x?,y?,canvasX?,canvasY?}, copy_frame_element {same input as move_frame_element; copies, the source keeps the element}, create_formats {frameId,targets:[{format:1:1|4:5|9:16|16:9}|{size:{width,height}}]} (editable copies of a frame in other formats, content refitted, placed to its right), export_selection {frameIds?,elements?:[{frameId,elementId}],rows:[{format:png|jpg|webp|svg|pdf|lottie|dotlottie,by:scale|width|height,value,suffix?,quality?,transparent?}],name?} (one file or a zip; a pdf row is one file, a page per frame; svg/pdf are true vector, with shapes as paths and text as outlines; lottie (.json) and dotlottie (.lottie) are the frame animation, up to 30 s, text as shapes, no browser needed; answers url, and skipped = what a vector or Lottie file could not draw), place_in_frame {nodeId,toFrameId?,x?,y?}, draw_frame {canvasId,x,y,w,h?,format?,still?} (an empty frame, like the frame tool; a preset format sets h from w; still? = seconds to keep, making it a still graphic such as a post or poster), draw_element {canvasId,drawn:{tool:text|rectangle|ellipse,box:{left,top,width,height}}|{tool:pen,path}} (a free Text/Box/Ellipse/Path on the canvas, outside any frame), group_elements {canvasId,nodeIds} (2+ free elements into one Group), ungroup_element {canvasId,nodeId}, rotate_group {canvasId,nodeId,degrees} (turns the Group and its members around its centre), move_group {canvasId,nodeId,x,y} (moves the Group and its members), scale_group {canvasId,nodeId,width,height} (resizes the Group and scales its members), show_run {nodeId,runId} (show an older result), sync_node {nodeId} (products, social feed), preview_workflow {canvasId,nodeIds}, cancel_workflow {workflowId}, cancel_render {nodeId}, withdraw_from_gallery {itemId}. Upload a file into a new node: request_upload {fileName,mimeType,bytes} (checked like the canvas upload: image/document 4MB, video 200MB) answers path + uploadUrl; PUT the bytes there with the Content-Type, then register_upload {canvasId,path,fileName,mimeType,bytes,x?,y?} answers node + asset. Copy a picture or video from a link into the project library: import_link {url} answers asset (use its id in a media prop; a raw link does not render in frames). Custom voices: list_voices {}, voice_library {search?,language?,gender?,accent?,useCase?,page?}, use_library_voice {ownerId,voiceId,name}, save_voice {generatedVoiceId,name,description?}, delete_voice {id}. Spends credits: run_node {nodeId,medium,prompt?,model?,params?,provider?,expectedVersion}, image_tool {nodeId,tool:remove_background|upscale|split_layers|inpaint|outpaint,factor?:2|4,prompt?,mask?,extend?} (upscale 2x or 4x; split_layers makes base + layers kept on the node; inpaint repaints a mask of strokes/regions as fractions, needs prompt and mask; outpaint grows sides by extend {left,top,right,bottom} fractions, needs prompt), run_node_loop {nodeId,confirm?}, retry_loop_combination {nodeId,outputListNodeId,label,runId?}, run_workflow {canvasId,nodeIds}, run_graph (same input as preview_run_graph; queued, each step after its inputs; cycles refused), design_voice {description} (previews to save_voice), read_video_reference {assetId} (a video asset into transcript, scenes with durations, on-screen text, UI, camera, transitions, pacing, palette, type; spends only on the first read), clone_voice {name,consentBasis:own_voice|consented_speaker,speaker?,attested:true,seconds:60-180,sampleBase64 (max 3MB),mimeType?} (only with the user’s consent). Unknown op answers the list; bad input answers the issues.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
project_id | string | yes | |
op | string | yes | |
input | object |
delete_row
Section titled “delete_row”Remove rows that exist, in your org. where is required — a delete with no filter is refused. At most 10 rows per call, counted before anything is removed. This does not come back. Free.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. Omit to use the default. | |
table | string | yes | |
where | array of object | yes |
describe
Section titled “describe”Families, op names, or exact input schemas.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | ||
family | canvas / frame / editor | ||
op | string | ||
ops | array of string |
describe_node_types
Section titled “describe_node_types”What data must look like on a nodes row, per type — the JSON Schema insert_row/update_row actually enforce on nodes, not a guess. Omit type for every type at once; name one to save tokens once you know which you need — an unknown type comes back as an error naming the ones that exist, so this list is never hand-maintained here. list holds N iteration values (images or text, never mixed); select picks exactly one item back out of a connected list, products or social_account_feed by a 1-based index — a synced catalogue or feed is an ordered list too, so select can pull one product or one post out of either the same way, exposing named outputs (out:images, out:text, and out:field:<field> for each entry of data.outputs — the fields per source are listed in its schema) that an edge picks with source_handle; effects holds a stack of image filters over an upstream image, each with its own params — set it with update_row, then render it with apply_effects; audio runs one ElevenLabs operation — audio_operations lists each one’s inputs, default model and price. Also returns recommended_models per medium (best, balanced, cheapest-good, each with price and release month) — prefer these over older models. Limits (aspect ratios, durations, prompt length) are NOT here — those come from get_media_models, because they are a fact of the model, not the node. Free.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. Omit to use the default. | |
type | string |
The one way to change a canvas: nodes, free elements, frames and what is inside a frame. You never pick an endpoint, the server routes by op. Op “describe”: {} gives the three families (canvas|frame|editor) with counts; {family} its op names, access (read|write|spend|editor) and one line; {op} or {ops:[…]} strict JSON input schemas. One op: {op, target?, element?, input?, version?, project_id?}. target = the node or frame id the op acts on (a frame op requires it); element = an element id inside that frame; they fill the id fields of the op’s input (nodeId, frameId, elementId, clip_id, clip_ids) unless you set them. project_id is needed by a canvas op without a target. Batch: op “batch” with ops:[{op,target?,element?,input?},...] (up to 500), canvas and frame ops mixed, run in order. Consecutive ops on the same frame are ONE revision, all or none. Across steps nothing is atomic: it stops at the first failure and answers applied (steps done), failed (index) and each step’s result; earlier steps stay. A later step cannot use an id created by an earlier one: create first, then batch. In a frame: element ids come from view canvas_summary/get; move or restyle with set_props/set_transform; version refuses a stale write. Free canvas element or node: move_node, resize_node, rename_node, update_node, delete_node. Between frames: move_frame_element. Names shared by two registries: the canvas op keeps the name, the frame tool becomes frame_<name>, the editor action editor_<name> (e.g. list_templates = canvas, frame_list_templates). Access in describe: read and write are free, spend costs credits (run_node, generate_voiceover), editor needs a chat turn in the app (recreate_ui, add_music). Errors answer the reason, with fix when known.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
project_id | string | ||
verbose | boolean | Whole documents back, not ids and changed fields. | |
ops | array of object | ||
op | string | An op name from describe. | |
target | string | Id of the node or frame the op acts on. | |
element | string | Id of an element inside the target frame. | |
input | object | ||
version | integer | Frame revision you read; a stale one is refused with 409. |
edit_storyboard_card
Section titled “edit_storyboard_card”Replace the text of one card of a motion video storyboard (card_id from get_storyboard).
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
node_id | string | yes | |
card_id | string | yes | |
text | string | yes |
enhance_prompt
Section titled “enhance_prompt”Rewrites a brief into the SHAPE the model you are about to render with wants — one reads labelled sections, another one flowing paragraph, another a command when it edits. Pass the model (get_media_models lists them) and use the prompt that comes back to render. It rewrites, it never invents: a rewrite that adds a subject, asks for readable text or states an aspect ratio is thrown away and the original returns with changed: false and the reason in notes, as does a model we have no guide for. Draws nothing, files nothing. Spends credits.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
prompt | string | yes | |
model | string | yes | |
shot_mode | hero / flat-lay / on-model / close-up / lifestyle / studio |
find_tools
Section titled “find_tools”Search tools and ops by keywords.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | ||
query | string | ||
family | canvas / frame / editor / motion / templates / storyboard / generation / effects / data / gallery / layouts / team / legacy |
forget_app_account
Section titled “forget_app_account”Deletes the test account and the browser session the project remembers; the chat asks for a test account again. Spends nothing.
| Field | Type | Required | Notes |
|---|---|---|---|
project_id | string | yes | The project id. |
get_app_account
Section titled “get_app_account”The TEST account of the user’s own app that the project chat remembers to log in and photograph its screens: login url, email, session expiry. Never the password. Reads only, spends nothing.
| Field | Type | Required | Notes |
|---|---|---|---|
project_id | string | yes | The project id. |
get_media
Section titled “get_media”View the image, video, audio, 3D model or text a node holds, a generation run produced, or an asset — by node_ids, run_ids and/or asset_ids. Per item: type, mime, width/height, duration, and two signed links: preview_url (images: 1024px long edge, valid 5 minutes — FETCH THIS to look at the image and judge it against the prompt) and full_url (the original file, valid 1 hour — give this to the user). Videos and audio have full_url only. Ids your org cannot see come back in missing. Reads only, spends nothing.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
node_ids | array of string | ||
run_ids | array of string | ||
asset_ids | array of string |
get_motion_embed
Section titled “get_motion_embed”Whether the web embed of a motion video is published, its public url, the loader snippet and the saved revision. The self-contained HTML file (no hosting) is downloaded with feega motion embed <node> --download <file>, or GET /api/v1/motion/{node_id}/embed/bundle. Reads only.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
node_id | string | yes |
get_motion_run
Section titled “get_motion_run”State of an ask_motion_agent run: status (running, done, failed, expired), the agent reply, the summary of its edits, the new revision version (null when nothing was saved), cost_usd and editor_url. Reads only.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
run_id | string | yes |
get_motion_summary
Section titled “get_motion_summary”Prefer view get. The saved state of a motion video: revision version, last change and who made it, size, fps, duration and every track and clip with start/duration in seconds. Reads only, spends nothing.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
node_id | string | yes |
get_render
Section titled “get_render”State of a render_video run: status (running, done, failed, expired), and when done asset_id and a signed file_url valid one hour; error when failed. Reads only.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
run_id | string | yes |
get_storyboard
Section titled “get_storyboard”The storyboard canvas linked to a motion video: its cards left to right (node_id, text, the clip_ids that play it), the pictures and clips on it with their asset ids and the card each feeds, and the card-to-card flow. storyboard: null when none was written. Reads only.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
node_id | string | yes |
insert_row
Section titled “insert_row”Add ONE row to any table in your org. org_id is filled in for you; naming a different one is refused, not quietly corrected. Never replaces anything — a row that already exists comes back as a collision, and changing it is update_row. Several jsonb columns are checked against a real shape before writing (nodes.data by type — call describe_node_types first; posts.media, ad_campaigns.targeting/placements, canvases.viewport too); a rejection names the exact field. On nodes_connections, an edge into a node whose model is uncensored is refused — those nodes take no input of any kind. Others are deliberately free-form. Free.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. Omit to use the default. | |
table | string | yes | |
values | object | yes | |
verbose | boolean | Whole row back, not id and changed fields. |
list_effects
Section titled “list_effects”Every image effect apply_effects accepts, with its params (range, options, default), and the workspace’s custom effects (write_effect) as custom: [{ effect_id, name, version, state, step }]: put step ({ id: "custom", ref }) in an apply_effects stack. Reads only, spends nothing.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. |
list_layouts
Section titled “list_layouts”The workspace’s custom composition layouts: id, name, version, spec. Reads only, spends nothing.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. |
list_motion_revisions
Section titled “list_motion_revisions”Every saved revision of a motion video, newest first: version, who saved it (actorKind user or agent), the summary of the change and how many clips it had, so a broken or emptied version can be told from a good one. Reads only.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
node_id | string | yes |
list_motion_templates
Section titled “list_motion_templates”Ready-made pieces to drop into a motion video (built-in and saved by the org), e.g. builtin:prompt-input, a prompt field that types, presses send and thinks. Each with id, seconds, its card (roles such as opener/feature/proof/closer, energy, loops, onScreen beat by beat with seconds, edges start→end with a suggested transition, goodFor) and its fields: key, type (text, number min..max, color #rrggbb, boolean, select options), group and default. Plan a video as sections and pick one template per section by card. Reads only, free.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. |
list_motion_videos
Section titled “list_motion_videos”The motion videos (motion canvas nodes) of the org, newest first, optionally of one project: node_id, name, project_id, canvas_id, format, saved revision version (0 = empty), signed poster_url and last_render_url (one hour, null when none) and editor_url (the canvas with the frame selected). Use it to find the node_id the other motion tools take. Reads only.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
project_id | string |
list_orgs
Section titled “list_orgs”The organisations the user belongs to, with their role; active: true is the one every tool works in when org is omitted. Free, reads only.
No input.
list_shader_effects
Section titled “list_shader_effects”The GPU shader effects (open-source shaders library, WebGPU) the motion agent adds with add_shader_effect: gradients, noise, glass, metal, light, distortions, wipes, blurs. Each with category, source (generator, or filter over a picture), live (cursor effects: interactive embeds only), its knobs with ranges and whether they take keyframes, and colours. Name one in ask_motion_agent, e.g. “add an iris-wipe reveal on the product shot”. Reads only.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. |
list_team
Section titled “list_team”Members with role, pending invites and whether the invite link is on, for org_id (default: the active org). Free, reads only.
| Field | Type | Required | Notes |
|---|---|---|---|
org_id | string |
load_tools
Section titled “load_tools”Add tools to this session list.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | ||
names | array of string | yes |
make_effects_pair
Section titled “make_effects_pair”For an effects node with a shape-cutout step: creates its twin (same shapes and seed, other side — shapes over the image vs fill with holes), wired to the same image, and renders it. Returns { node_id, asset_id }. Free.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
node_id | string | yes |
model_allowlist
Section titled “model_allowlist”Which image, video and 3D models the org offers. Without medium it reads: ids per medium, an empty list meaning every model. With medium (image, video, model3d) and model_ids it replaces that medium list, admins only and only when the user asks; an empty model_ids allows every model again. Free.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | ||
medium | image / video / model3d | ||
model_ids | array of string |
motion_budget
Section titled “motion_budget”What a motion video has spent on AI across all its agent turns (spent_usd) and what it may spend (cap_usd). When an ask returns video_budget, the agent stopped because the video used its budget: its work is saved. action: "raise" adds raise_usd to the cap (only when the user asked to continue), then ask_motion_agent continues.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
node_id | string | yes | |
action | read / raise |
motion_editor_op
Section titled “motion_editor_op”Deprecated, use edit. The actions the frame editor page runs on a motion node (node_id), same answers as the page, with input in camelCase. Op “describe” with {} lists them with one line each, with {op} gives its input schema. Reads: editor_session {briefIds?} (everything the canvas loads for a frame: head, assets, tokens, templates, render state, gallery), read_head {} (version, full doc, actorKind), render_status {} (latest server render), batch_status {} (latest batch render), list_fonts {} (uploaded font families of the org, with their files). Writes: save_doc {version,doc,summary?} (whole doc; 409 answers the head), apply_ops {version,ops,summary?} (doc ops, rebased on newer edits), record_export {path,width,height,seconds} (an mp4 already in storage becomes the render asset), upload_font {path} (a TTF, OTF, WOFF or WOFF2 already in canvas-assets under the org fonts folder; joins the org library), rename_font {family,to}, delete_font {family}, analyze_sounds {assetIds} (tempo, beats, speech), template_sounds {doc,clipId} (lays the template clip SFX; answers the doc), save_template {doc,name,description,compId?,posterFrame?}. Spends credits: generate_sound {sound:voice|music,text,seconds?} (answers assetId, url), render_batch {version,rows:[{name,values}],settings?} (one server render per row of template field values; poll batch_status). Unknown op answers the list; bad input answers the issues; a stale version answers 409.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
node_id | string | yes | |
op | string | yes | |
input | object |
motion_tool
Section titled “motion_tool”Deprecated, use edit. Every tool of the motion editor agent (add_clip, set_props, set_keyframes, add_template, set_canvas, export_image… over 140), run directly on a video with no AI. Free except generate_voiceover {text,start?,voice_id?}, which makes a voice-over and spends credits. No tool: lists them by name. tool alone: its description and JSON input schema. tool with node_id: runs it on the saved video with input; an edit is saved as a new revision (version answers the new one; pass the version you read to refuse a stale write with 409; a tool that refuses is an error with its reason). Prefer tool “batch” with input { ops: [{ tool, input }, …] } (up to 500): every op in one revision, all or none. Still graphics: set_canvas with still (seconds of the frame) and format “4:5” post, “9:16” story or “A poster”; export_image (format png, jpg, webp; scale 1 or 2) saves the image to the project and returns its url. Tools that need a chat turn (research, sub-agents) answer with an error: use ask_motion_agent for those.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
tool | string | ||
node_id | string | ||
input | object | ||
version | integer |
new_motion_from_template
Section titled “new_motion_from_template”Create a new motion video that already holds a template (id from list_motion_templates) at 0s, sized to format (16:9 default; 9:16 story, 4:5 post, “A poster”), in project (default: the most recently active). still: seconds of the one frame to keep, making it a still graphic (post, poster) instead of a video. Returns node_id and editor_url; change its fields with add_motion_template vars or ask_motion_agent. No AI, free.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
template | string | yes | |
format | 16:9 / 9:16 / 1:1 / 4:5 / 1:1 1440 / A poster | ||
project | string | ||
still | number |
patch_effect
Section titled “patch_effect”Edits a custom effect: edits [{ find, replace }] applied in order on its frag, params replaces the list. version is the one list_effects or write_effect returned; a stale one answers 409 conflict. Returns { effect } with the new check. Spends no credits.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
effect_id | string | yes | |
version | integer | yes | |
edits | array of object | ||
params | array of object |
patch_layout
Section titled “patch_layout”Replaces the spec of a custom layout at its version (list_layouts); a stale one is a 409. Spends no credits.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
layout_id | string | yes | |
version | integer | yes | |
spec | object | yes |
preview_node_loop
Section titled “preview_node_loop”How many combinations run_node_loop would queue on this node right now, and what they would cost — reads only, spends nothing. Call this before run_node_loop when the count is not already known, rather than guessing at whether confirm will be needed.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
node_id | string | yes |
publish_motion_embed
Section titled “publish_motion_embed”Host the interactive web export of the saved revision on feega and return the public url and a snippet to paste into any site: feega’s loader script and a <feega-motion> element that fills 100% of its box, reading playback and scroll length from feega (keeps pointer, tilt, scroll, key and tap input; live components such as games and generative pieces run live there). Publishing again updates the same embed in place, so the site needs no new paste. Also returns react and flutter: the same embed for a React app (@feega/motion-react) or a Flutter app (feega_motion), running the same player. action: "unpublish" takes it down. Videos from an uncensored project are refused (403, refusal). Free.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
node_id | string | yes | |
action | publish / unpublish |
publish_to_gallery
Section titled “publish_to_gallery”Publish a motion node to the public gallery, free, so anyone can remix it. Only when the user asks. Refused for uncensored projects, real brands (their logo, a script about a real brand, logos or pictures imported from a website) and content the moderation refuses. title up to 80 characters, description up to 500, up to 8 one-word tags. Returns the gallery id and url.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
node_id | string | yes | |
title | string | yes | |
description | string | ||
tags | array of string |
READ ANYTHING in your org: projects, canvases, nodes, connections, assets, posts, ads, products, social accounts — every table, scoped to your org and nothing else. No SQL: name a table, columns and where filters, and it issues one PostgREST read. Omit table to list every name. A project has no brand until one is attached (projects.brand_id is nullable, and that is the normal case). A canvas belongs to a project; nodes and their connections belong to a canvas. A post (posts table) is the promoted artifact — caption, media, brand — different from a node, which is raw canvas material; post_sources links a post back to the nodes it came from. Free.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. Omit to use the default. | |
table | string | ||
columns | array of string | ||
where | array of object | ||
order | object / array of object | ||
embed | array of object | ||
offset | integer | ||
cursor | string | next_cursor of the previous page. | |
verbose | boolean | Long values whole, bigger page. | |
count | estimated / exact | ||
limit | integer |
remix_gallery_item
Section titled “remix_gallery_item”Remix a gallery item, free: copies its video and files into a new motion node of project_id (on canvas_id, or on the Motion canvas), with its main texts, colours, logo and media exposed as fields. Returns node_id and editor_url. Then offer to put the user brand on it with ask_motion_agent.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
item_id | string | yes | |
project_id | string | yes | |
canvas_id | string |
render_video
Section titled “render_video”Render the saved revision of a motion video to MP4. Default mode: "browser": free, returns a render_url — a one-time link (expires in 30 minutes, bound to this revision) the user opens on any device; it renders in their browser and saves the file to the project. Show the link to the user. With no user, open headless_url in any headless Chromium: it starts with no click; keep it open until get_render says done. mode: "server" renders on the farm, the same path and credit gate as the editor Render button; while server rendering is closed for everyone it answers 403 server_render_unavailable. A live component (a game or generative piece) cannot be seeked: the video shows a still of it; publish it as an embed instead. Poll get_render with the run_id for the file.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
node_id | string | yes | |
mode | browser / server | ||
resolution | 720p / 1080p / 1440p / 2160p | ||
format | string | server only: mp4-h264, mp4-h265, prores-422hq, prores-4444, webm-alpha, png-sequence, gif, apng | |
quality | standard / high / max | ||
fps | number / number / number / number / number / number | 120 renders on our servers only | |
gif | object | format gif only: loop forever (default), once or boomerang; fps 8-30 (15); width 64-1920 px (640); the video can be up to 30 s |
restore_motion_revision
Section titled “restore_motion_revision”Put an earlier revision of a motion video back (number from list_motion_revisions). It is saved as a NEW revision: no history is deleted, and restoring again undoes it. Free.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
node_id | string | yes | |
version | integer | yes |
run_node_generation
Section titled “run_node_generation”Generate into an existing canvas node — text, image, video, audio or model3d. This is the same engine the canvas Generate button calls; it never creates a node (insert_row does that). medium MUST match the node’s own type, or the call is refused before anything is spent. Pass version as the node’s current nodes.version: a stale value comes back conflict (never a silent overwrite) — re-read the node and retry with the fresh version. A video NEVER returns finished here: it comes back queued with an external_job_id on the run, and the render lands later, asynchronously — the node stays running until a later tick deposits the asset. Poll the node (query) rather than expecting a file now. An audio node runs one ElevenLabs operation set in params.operation (see audio_operations in describe_node_types); describe_node_types with type: audio also lists the voices. Audio dubbing is queued like a video. A model3d node turns ONE connected image into a GLB 3D model on a wiro/ image-to-3D model. With no image but a prompt or connected text, it first draws a white-background product shot on the cheapest image model (billed too), then models that; with neither it is refused. Settings go in params (Trellis/Pixal3D pipeline_type, Hunyuan3D generate_texture). A finished result returns asset_ids and media with preview_url/full_url (see get_media). Omit model to keep the node’s own model, or the recommended balanced one for the medium when it has none (describe_node_types lists the recommended ones). A model the canvas does not offer is refused with the recommended alternatives; an old or weak one still runs but the result carries a warning naming the recommended one. Models whose id starts with wiro/ or higgsfield/ run on that provider and are always queued like a video, after a safety screen that refuses with a readable reason. Some models run first on a cheaper route (Kie.ai) at its price and fall back to their own provider if it fails; you are charged once. canvas_tool list_models lists ids, providers and prices. Uncensored models run only in an uncensored project, when the org owner turned them on in Settings; minors and real, identifiable people are refused regardless. An uncensored model takes NO input of any kind — no upstream connections, no picked references, no image/mask/init params — and the call is refused before anything is spent if any are present. Spends credits; a credits_exhausted failure means the org is out. variants (1, 2, 4 or 8; video up to 4) makes several results in one call and spends that many times the price of one run: into: "nodes" (default) creates new output nodes next to this one, wired from the same inputs, and returns their nodeIds; into: "history" lands every result in this node’s own history, the last one shown. The org’s model allow-list and spend caps apply to the whole batch, which is refused before anything is spent if either blocks it. cancel_node_loop also stops a variant batch still running on this node.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
node_id | string | yes | |
variants | integer | 1, 2, 4 or 8 (video up to 4). Omit for one result. | |
into | nodes / history | With variants > 1: “nodes” (default) or “history”. | |
medium | text / image / video / audio / model3d | yes | |
prompt | string | yes | |
model | string | ||
provider | string | Which provider runs the model: a routes[].provider from canvas_tool list_models (e.g. “kie”, “openrouter”). Omit or “auto” for the cheapest healthy one with automatic fallback; a chosen provider that fails is reported, never silently replaced. | |
version | integer | yes | |
params | object |
run_node_loop
Section titled “run_node_loop”QUEUES many combinations from a node’s iterate wires (or plain “repeat N” variants when it has none) to run through the SAME engine run_node_generation calls — one real run per combination, never a copy of it. This call returns as soon as the queue is written, NOT when the images exist: combinations run a few at a time as a background tick drains the queue over the following minutes, so 1000 combinations take longer than 50 to finish. Up to 50 queues on the call; above 50 it comes back needs_confirmation with the count and the credit cost — call again with confirm: true; above 1000 it is refused outright and the loop must be split. Credits for the WHOLE loop are checked up front, not discovered empty halfway. A failed combination never stops the others; results land in an output list node next to this one as they finish, each item labelled with which values produced it — poll that node (query) to see progress, do not expect it done here.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
node_id | string | yes | |
confirm | boolean | Required (true) to queue above 50 combinations. |
search_gallery
Section titled “search_gallery”Search the public gallery of free motion videos and compositions anyone can remix (many by Feega). Filters: query (title words), kind (motion, composition), format (16:9, 9:16, 1:1, 4:5), duration (short up to 6 s, medium 6 to 15 s, long over 15 s), tag. Returns id, title, author, format, seconds, remixes and url. Free, reads only.
| Field | Type | Required | Notes |
|---|---|---|---|
query | string | ||
kind | motion / composition | ||
format | 16:9 / 9:16 / 1:1 / 4:5 / 1:1 1440 | ||
duration | short / medium / long | ||
tag | string |
share_motion_frame
Section titled “share_motion_frame”Create the public viewer link of ONE frame: a clean full-screen page that plays it on a loop, with tap to play and swipe between the canvas’s shared frames on a phone. Publishes the frame’s web embed if needed and turns the canvas share link on; returns url (the viewer) and embed_url. Turning the canvas share off kills every frame link. Videos from an uncensored project are refused (403, refusal). Free.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
node_id | string | yes |
spend_caps
Section titled “spend_caps”The spend caps of the org. Without scope it reads them. With scope (org_member: each member anywhere; project_member: each member in project_id; project_total: the project as a whole) and cap_usd it sets one, admins only and only when the user asks; cap_usd null removes it. reset is none or monthly. A run refused by a cap answers with the error cap_reached. Free.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | ||
scope | org_member / project_member / project_total | ||
project_id | string | ||
cap_usd | number / null | ||
reset | none / monthly |
team_op
Section titled “team_op”One organisation or team change, only when the user asks; org_id defaults to the active org. switch_org (org_id), create_org (name); invite (email, role admin|member|viewer), resend_invite/revoke_invite (invite_id), invite_link (new link, joins as viewer; old one stops) / disable_invite_link, set_role (user_id, role), remove_member (user_id), leave, transfer_ownership (user_id; owner only, you become admin). Free organisations have limited editor seats: a seat_limit answer carries upgrade_path; viewers are free.
| Field | Type | Required | Notes |
|---|---|---|---|
op | switch_org / create_org / invite / resend_invite / revoke_invite / invite_link / disable_invite_link / set_role / remove_member / leave / transfer_ownership | yes | |
org_id | string | ||
name | string | ||
email | string | ||
role | admin / member / viewer | ||
invite_id | string | ||
user_id | string |
unload_tools
Section titled “unload_tools”Drop loaded tools.
| Field | Type | Required | Notes |
|---|---|---|---|
names | array of string | yes |
update_row
Section titled “update_row”Change columns on rows that already exist in your org. Only the columns you send are touched. where is required — an update with no filter is refused. At most 50 rows per call, counted before anything is written. Free.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. Omit to use the default. | |
table | string | yes | |
where | array of object | yes | |
values | object | yes | |
verbose | boolean | Whole rows back, not ids and changed fields. |
Read the canvas in one call; free. Op “describe” lists the ops with strict schemas. canvas_summary {canvas_id}: every node (id, type, title, x/y, size, inputs/outputs, last run status) and, per frame, its element tree (id, kind, name, bounds in px, text, start/duration seconds). get {id} one node in full, or {id, frame_id} one element of a frame with props, transform, keyframes. activity {canvas_id, since?}: recent structural events (who/what/when), runs still working; presence is not readable from the server and is reported as unavailable. snapshot {node_id, time?, width?}: the frame as an IMAGE you can see, with the quality gate; drawn by the server renderer, or by the renderer of the deployed app when the server has none (answers server_frames_unavailable, 503, only when neither is reachable); a whole canvas, a region or one element cannot be drawn alone, snapshot its frame. About 10 snapshots a minute per workspace. Also reads: list_nodes / canvas_snapshot (raw) via edit; the saved doc via edit get_motion_doc; tables via query.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
op | string | yes | |
input | object |
view_motion_frames
Section titled “view_motion_frames”Prefer view snapshot. Draw the saved revision of a motion video at up to 6 exact times (seconds) and see them as JPEG images, with the quality gate the editor agent uses: quality lists every problem found (clipped or tiny text, flat or blank frames, flashes, missing music…), blocking the ones that must be fixed before delivery. width is the longest side in pixels (default and max 960). Use it to check a video before and after ask_motion_agent. Free; about 10 calls a minute per workspace.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
node_id | string | yes | |
times | array of number | yes | |
width | integer |
write_effect
Section titled “write_effect”Writes a custom shader effect for the whole workspace (same name replaces it): frag is a GLSL ES 1.0 body defining vec4 effect(vec2 uv), with u_src (the picture), u_res, u_time, u_seed, v_uv, hash(vec2) and noise(vec2) given, and each param a uniform u_<key> (number → float, color → vec3, seed → float; keys src, res, time, seed are taken). No #extension, no derivatives, loops bounded at 64, at most 16 texture2D, 12 KB. Returns { effect } with its check (passed, failed + problems, unchecked). Spends no credits.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
name | string | yes | kebab-case, e.g. vhs-glow |
frag | string | yes | |
params | array of object |
write_layout
Section titled “write_layout”Writes a custom composition layout for the workspace (same name replaces it). spec: { kind: "spec", slots, place, cards?, camera?: fixed|selected, motion?: cycle|ping-pong|linear, params?, tilt?, scale?, animate? }; place is { kind: "grid", columns, gapX, gapY }, { kind: "ring", radius }, { kind: "line", gap, axis } or { kind: "scatter", spread, depth, seed }; animate items { prop: x|y|z|rotX|rotY|rotZ|scale|opacity, fn: sin|linear|ease, amp, freq, phase: { column, row, index } }; any number may be { param } of a declared range param. Ask ask_motion_agent to put it on a composition. Spends no credits.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
name | string | yes | kebab-case |
spec | object | yes |
write_storyboard
Section titled “write_storyboard”Lay out a motion video as a storyboard canvas: one card per beat, story order left to right, stronger emotion higher. Each beat: act (problem, solution, proof, claim), kind (title_card, ui_beat, product_shot, scene, logo), title, intent, on_screen, emotion, intensity 0-1, duration seconds, visual, music, media (project image/video asset ids), branch_of (index of an earlier beat it replaces). Replaces the cards written before; what the user added stays.
| Field | Type | Required | Notes |
|---|---|---|---|
org | string | Which org, if you belong to more than one. | |
node_id | string | yes | |
beats | array of object | yes |