Apply a canvas changeset
import { FloraClient } from '@flora-ai/flora';
const client = new FloraClient({ apiKey: process.env['FLORA_API_KEY'] });
const canva = await client.projects.canvas.applyChangeset({ workspaceId: '<workspaceId>', projectId: '<projectId>', add: [ { ref: 'hero', type: 'image', }, ], update: [ { id: 'n7', }, ], connect: [ { from: 'n7', to: 'n7', }, ], disconnect: [ { from: 'n7', to: 'n7', }, ], remove: [ { id: 'n7', }, ],});console.log(canva);curl -X POST 'https://app.flora.ai/api/v1/workspaces/<workspaceId>/projects/<projectId>/canvas/changeset' \ -H 'Authorization: Bearer $FLORA_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "add": [ { "ref": "hero", "type": "image" } ], "update": [ { "id": "n7" } ], "connect": [ { "from": "n7", "to": "n7" } ], "disconnect": [ { "from": "n7", "to": "n7" } ], "remove": [ { "id": "n7" } ]}'Edits a project canvas: add, update, connect, disconnect and remove operations validate together before writes begin. Invalid operations reject the request, and every cause is reported with a machine-readable code in the error’s fields array. Authored content lives in document: an add of type timeline or deck may carry one, and an update replaces a timeline or deck document wholesale, guarded by base_revision so a write based on a stale read is rejected with revision_conflict instead of overwriting someone else’s edit. Documents are validated against their authoring limits. Deck updates require base_revision and use observed Liveblocks revisions; simultaneous collaborators and undo retain the editor’s existing semantics. Deck content and Timeline drafts use separate storage, so a mixed changeset is not a cross-store transaction. Deck writes do not render or export a presentation. Operations apply in the order add, update, connect, disconnect, remove, with groups created before their members — so one call can create a group, fill it, wire the new nodes to existing ones by the ref names it chose, and delete something else. Nodes are addressed by the short id or node UUID the project graph endpoint reports, or by a ref declared by an add operation in the same request. REMOVE IS IMMEDIATE AND IRREVERSIBLE through the API: there is no confirmation step and no undo, deleting a node also deletes its edges and any group members, so confirm destructive changesets with your user before sending them. The revision returned is the same change-detection marker the project graph endpoint reports, so it can be compared directly against a later read. Mutating public API requests support an optional Idempotency-Key header for client retries; duplicate keys within two hours return idempotency_duplicate.
Error responses use the standard error body.
Authorizations
Section titled “Authorizations ”Parameters
Section titled “ Parameters ”Path Parameters
Section titled “Path Parameters ”Workspace identifier
Workspace identifier
Project identifier
Project identifier
Request Body
Section titled “Request Body ”object
Nodes to create. Groups are created before their members.
object
Caller-chosen handle for the new node, echoed back in created with its real ids. Usable as a connect or group target inside this same changeset. Must not collide with a live node id.
Node type to create, in the agent vocabulary the graph read reports
Display label pinned on the node
Generation prompt, stored in the node’s model parameters. Mutually exclusive with content_url.
Model name or endpoint id, as the graph read reports them. Omit to take the default model for the node’s modality.
Model parameters, validated against the model’s schema. Invalid values reject the whole changeset rather than being coerced.
object
Absolute canvas position. Omit to place the node automatically below the existing canvas content.
object
Absolute horizontal canvas coordinate
Absolute vertical canvas coordinate
Group to parent this node into: an existing group’s short id or UUID, or the ref of a group created by this same changeset.
HTTPS URL of existing image, video, or audio to place instead of generating. The media is copied onto Flora’s CDN and the node becomes a static block. Mutually exclusive with prompt, model, and params.
object
Document schema version; currently 1
Frames per second of the composition
Even number of pixels
Even number of pixels
Lanes, first is the bottom-most
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Display name of the lane
Item ids in this lane, bottom to top of the z-order. Every id must exist in items.
Clips keyed by item id. At least one item is required.
object
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Start frame on the composition timeline. Frames, not seconds.
Length in frames. The cut is never guessed from the media.
Top edge in composition pixels
Left edge in composition pixels
Width in composition pixels
Height in composition pixels
Key of a video asset in assets
Offset into the source video where playback starts. Seconds.
Gain in dB; 0 leaves the source as is
Speed multiplier; 1 is real time
Visual fade-in length in seconds
Visual fade-out length in seconds
Fraction of the item cropped from the left
Fraction of the item cropped from the top
Fraction of the item cropped from the right
Fraction of the item cropped from the bottom
Corner radius in composition pixels
Rotation in degrees
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Start frame on the composition timeline. Frames, not seconds.
Length in frames. The cut is never guessed from the media.
Top edge in composition pixels
Left edge in composition pixels
Width in composition pixels
Height in composition pixels
Key of an image asset in assets
Visual fade-in length in seconds
Visual fade-out length in seconds
Fraction of the item cropped from the left
Fraction of the item cropped from the top
Fraction of the item cropped from the right
Fraction of the item cropped from the bottom
Corner radius in composition pixels
Rotation in degrees
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Start frame on the composition timeline. Frames, not seconds.
Length in frames. The cut is never guessed from the media.
Top edge in composition pixels
Left edge in composition pixels
Width in composition pixels
Height in composition pixels
Key of a gif asset in assets
Visual fade-in length in seconds
Visual fade-out length in seconds
Fraction of the item cropped from the left
Fraction of the item cropped from the top
Fraction of the item cropped from the right
Fraction of the item cropped from the bottom
Corner radius in composition pixels
Rotation in degrees
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Start frame on the composition timeline. Frames, not seconds.
Length in frames. The cut is never guessed from the media.
Top edge in composition pixels
Left edge in composition pixels
Width in composition pixels
Height in composition pixels
Key of an audio asset in assets
Offset into the source audio where playback starts. Seconds.
Gain in dB; 0 leaves the source as is
Speed multiplier; 1 is real time
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Start frame on the composition timeline. Frames, not seconds.
Length in frames. The cut is never guessed from the media.
Top edge in composition pixels
Left edge in composition pixels
Width in composition pixels
Height in composition pixels
CSS color of the rectangle
Visual fade-in length in seconds
Visual fade-out length in seconds
Corner radius in composition pixels
Rotation in degrees
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Start frame on the composition timeline. Frames, not seconds.
Length in frames. The cut is never guessed from the media.
Top edge in composition pixels
Left edge in composition pixels
Width in composition pixels
Height in composition pixels
CSS color
Google Fonts family name
Font variant (“normal” or “italic”) and CSS weight (“400”, “700”, …)
object
Font size in composition pixels
Line height as a multiplier
Letter spacing in composition pixels
Text outline width in composition pixels
CSS color
Editor behavior: true re-measures the box when the text changes
Rotation in degrees
Visual fade-in length in seconds
Visual fade-out length in seconds
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Start frame on the composition timeline. Frames, not seconds.
Length in frames. The cut is never guessed from the media.
Top edge in composition pixels
Left edge in composition pixels
Width in composition pixels
Height in composition pixels
Key of a caption asset in assets
CSS color
Google Fonts family name
Font variant (“normal” or “italic”) and CSS weight (“400”, “700”, …)
object
Font size in composition pixels
Line height as a multiplier
Letter spacing in composition pixels
Text outline width in composition pixels
CSS color
CSS color of the word being spoken
Visual fade-in length in seconds
Visual fade-out length in seconds
Media keyed by asset id. Every media item’s asset_id must be a key here.
object
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Display name in the editor. Defaults to the last path segment of media_url.
Defaults from the asset type and the media_url extension.
Canvas node whose output seeded this asset, when known. Read-only.
Durable https URL of the media the renderer fetches. Flora’s own asset URLs and any public https URL are accepted.
Native media width in pixels
Native media height in pixels
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Display name in the editor. Defaults to the last path segment of media_url.
Defaults from the asset type and the media_url extension.
Canvas node whose output seeded this asset, when known. Read-only.
Durable https URL of the media the renderer fetches. Flora’s own asset URLs and any public https URL are accepted.
Native media width in pixels
Native media height in pixels
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Display name in the editor. Defaults to the last path segment of media_url.
Defaults from the asset type and the media_url extension.
Canvas node whose output seeded this asset, when known. Read-only.
Durable https URL of the media the renderer fetches. Flora’s own asset URLs and any public https URL are accepted.
Native media width in pixels
Native media height in pixels
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Display name in the editor. Defaults to the last path segment of media_url.
Defaults from the asset type and the media_url extension.
Canvas node whose output seeded this asset, when known. Read-only.
Durable https URL of the media the renderer fetches. Flora’s own asset URLs and any public https URL are accepted.
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Display name in the editor. Defaults to the last path segment of media_url.
Defaults from the asset type and the media_url extension.
Canvas node whose output seeded this asset, when known. Read-only.
Authored Deck content: 1–200 slides, up to 256 layers per slide, and at most 4 MiB of UTF-8 JSON.
object
object
object
object
object
object
object
object
object
object
object
object
object
object
object
Dimensionless size multipliers. Text uses frame.pixel_width by round(font_size * 7.5) as its reference box (font_size defaults to 144); shapes use 512 by 512; media uses its resolved source dimensions. Divide the desired pixel width and height by the reference dimensions. For a 1200 by 240 text box at font_size 96 on a 1920-wide frame, use x: 0.625, y: 0.3333333333333333.
object
object
Typography only; the rendered text or live binding belongs in content.
object
object
object
Dimensionless size multipliers. Text uses frame.pixel_width by round(font_size * 7.5) as its reference box (font_size defaults to 144); shapes use 512 by 512; media uses its resolved source dimensions. Divide the desired pixel width and height by the reference dimensions. For a 1200 by 240 text box at font_size 96 on a 1920-wide frame, use x: 0.625, y: 0.3333333333333333.
object
object
object
object
object
object
Dimensionless size multipliers. Text uses frame.pixel_width by round(font_size * 7.5) as its reference box (font_size defaults to 144); shapes use 512 by 512; media uses its resolved source dimensions. Divide the desired pixel width and height by the reference dimensions. For a 1200 by 240 text box at font_size 96 on a 1920-wide frame, use x: 0.625, y: 0.3333333333333333.
object
object
object
object
object
object
object
object
object
Body of a notes node: plain text, newlines significant, at most 20000 characters. Notes are canvas documentation — they generate nothing and spend nothing. Rejected on every other node type, which take prompt instead.
Existing nodes to modify. One operation per node.
object
Node to modify: its short id or UUID
Replacement display label
Replacement generation prompt
Replacement model name or endpoint id
Model parameters, merged key by key into the node’s stored parameters. Omitted keys survive; a named key is overwritten. On an action node these are the action’s own parameter values.
object
New absolute canvas position
object
Absolute horizontal canvas coordinate
Absolute vertical canvas coordinate
object
Document schema version; currently 1
Frames per second of the composition
Even number of pixels
Even number of pixels
Lanes, first is the bottom-most
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Display name of the lane
Item ids in this lane, bottom to top of the z-order. Every id must exist in items.
Clips keyed by item id. At least one item is required.
object
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Start frame on the composition timeline. Frames, not seconds.
Length in frames. The cut is never guessed from the media.
Top edge in composition pixels
Left edge in composition pixels
Width in composition pixels
Height in composition pixels
Key of a video asset in assets
Offset into the source video where playback starts. Seconds.
Gain in dB; 0 leaves the source as is
Speed multiplier; 1 is real time
Visual fade-in length in seconds
Visual fade-out length in seconds
Fraction of the item cropped from the left
Fraction of the item cropped from the top
Fraction of the item cropped from the right
Fraction of the item cropped from the bottom
Corner radius in composition pixels
Rotation in degrees
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Start frame on the composition timeline. Frames, not seconds.
Length in frames. The cut is never guessed from the media.
Top edge in composition pixels
Left edge in composition pixels
Width in composition pixels
Height in composition pixels
Key of an image asset in assets
Visual fade-in length in seconds
Visual fade-out length in seconds
Fraction of the item cropped from the left
Fraction of the item cropped from the top
Fraction of the item cropped from the right
Fraction of the item cropped from the bottom
Corner radius in composition pixels
Rotation in degrees
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Start frame on the composition timeline. Frames, not seconds.
Length in frames. The cut is never guessed from the media.
Top edge in composition pixels
Left edge in composition pixels
Width in composition pixels
Height in composition pixels
Key of a gif asset in assets
Visual fade-in length in seconds
Visual fade-out length in seconds
Fraction of the item cropped from the left
Fraction of the item cropped from the top
Fraction of the item cropped from the right
Fraction of the item cropped from the bottom
Corner radius in composition pixels
Rotation in degrees
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Start frame on the composition timeline. Frames, not seconds.
Length in frames. The cut is never guessed from the media.
Top edge in composition pixels
Left edge in composition pixels
Width in composition pixels
Height in composition pixels
Key of an audio asset in assets
Offset into the source audio where playback starts. Seconds.
Gain in dB; 0 leaves the source as is
Speed multiplier; 1 is real time
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Start frame on the composition timeline. Frames, not seconds.
Length in frames. The cut is never guessed from the media.
Top edge in composition pixels
Left edge in composition pixels
Width in composition pixels
Height in composition pixels
CSS color of the rectangle
Visual fade-in length in seconds
Visual fade-out length in seconds
Corner radius in composition pixels
Rotation in degrees
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Start frame on the composition timeline. Frames, not seconds.
Length in frames. The cut is never guessed from the media.
Top edge in composition pixels
Left edge in composition pixels
Width in composition pixels
Height in composition pixels
CSS color
Google Fonts family name
Font variant (“normal” or “italic”) and CSS weight (“400”, “700”, …)
object
Font size in composition pixels
Line height as a multiplier
Letter spacing in composition pixels
Text outline width in composition pixels
CSS color
Editor behavior: true re-measures the box when the text changes
Rotation in degrees
Visual fade-in length in seconds
Visual fade-out length in seconds
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Start frame on the composition timeline. Frames, not seconds.
Length in frames. The cut is never guessed from the media.
Top edge in composition pixels
Left edge in composition pixels
Width in composition pixels
Height in composition pixels
Key of a caption asset in assets
CSS color
Google Fonts family name
Font variant (“normal” or “italic”) and CSS weight (“400”, “700”, …)
object
Font size in composition pixels
Line height as a multiplier
Letter spacing in composition pixels
Text outline width in composition pixels
CSS color
CSS color of the word being spoken
Visual fade-in length in seconds
Visual fade-out length in seconds
Media keyed by asset id. Every media item’s asset_id must be a key here.
object
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Display name in the editor. Defaults to the last path segment of media_url.
Defaults from the asset type and the media_url extension.
Canvas node whose output seeded this asset, when known. Read-only.
Durable https URL of the media the renderer fetches. Flora’s own asset URLs and any public https URL are accepted.
Native media width in pixels
Native media height in pixels
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Display name in the editor. Defaults to the last path segment of media_url.
Defaults from the asset type and the media_url extension.
Canvas node whose output seeded this asset, when known. Read-only.
Durable https URL of the media the renderer fetches. Flora’s own asset URLs and any public https URL are accepted.
Native media width in pixels
Native media height in pixels
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Display name in the editor. Defaults to the last path segment of media_url.
Defaults from the asset type and the media_url extension.
Canvas node whose output seeded this asset, when known. Read-only.
Durable https URL of the media the renderer fetches. Flora’s own asset URLs and any public https URL are accepted.
Native media width in pixels
Native media height in pixels
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Display name in the editor. Defaults to the last path segment of media_url.
Defaults from the asset type and the media_url extension.
Canvas node whose output seeded this asset, when known. Read-only.
Durable https URL of the media the renderer fetches. Flora’s own asset URLs and any public https URL are accepted.
object
Caller-chosen identifier; survives verbatim and is how other fields refer to it
Display name in the editor. Defaults to the last path segment of media_url.
Defaults from the asset type and the media_url extension.
Canvas node whose output seeded this asset, when known. Read-only.
Authored Deck content: 1–200 slides, up to 256 layers per slide, and at most 4 MiB of UTF-8 JSON.
object
object
object
object
object
object
object
object
object
object
object
object
object
object
object
Dimensionless size multipliers. Text uses frame.pixel_width by round(font_size * 7.5) as its reference box (font_size defaults to 144); shapes use 512 by 512; media uses its resolved source dimensions. Divide the desired pixel width and height by the reference dimensions. For a 1200 by 240 text box at font_size 96 on a 1920-wide frame, use x: 0.625, y: 0.3333333333333333.
object
object
Typography only; the rendered text or live binding belongs in content.
object
object
object
Dimensionless size multipliers. Text uses frame.pixel_width by round(font_size * 7.5) as its reference box (font_size defaults to 144); shapes use 512 by 512; media uses its resolved source dimensions. Divide the desired pixel width and height by the reference dimensions. For a 1200 by 240 text box at font_size 96 on a 1920-wide frame, use x: 0.625, y: 0.3333333333333333.
object
object
object
object
object
object
Dimensionless size multipliers. Text uses frame.pixel_width by round(font_size * 7.5) as its reference box (font_size defaults to 144); shapes use 512 by 512; media uses its resolved source dimensions. Divide the desired pixel width and height by the reference dimensions. For a 1200 by 240 text box at font_size 96 on a 1920-wide frame, use x: 0.625, y: 0.3333333333333333.
object
object
object
object
object
object
object
object
object
The document revision read before editing. Required for Deck replacements. A differing observed revision returns revision_conflict; read again and reapply the intended edit. Deck revisions follow Liveblocks collaboration and undo and do not serialize simultaneous writers. Only meaningful alongside document; 0 is an empty Deck’s initial revision or a Timeline with no document yet.
Replacement body for a notes node, whole-body: at most 20000 characters. Rejected on nodes that carry no annotation body.
Edges to create. Either endpoint may be a ref created by this same changeset. The canvas carries one edge per pair, so a duplicate pair is skipped with a warning.
object
Source node reference
Target node reference
Target input slot, in the vocabulary the graph read reports: a modality word such as “image”, a named action or technique input, or “enabled” for the boolean gate. Omit to let the target take the edge by modality.
Edges to remove, addressed by their endpoints as the graph read reports them
object
Source node reference
Target node reference
Input slot of the edge to remove; omit to remove every edge between the pair
Nodes to delete. Their edges and any group members go too. Removal is immediate and cannot be undone through the API.
object
Node to delete: its short id or UUID
Responses
Section titled “ Responses ”Changeset applied.
object
Project identifier
Project canvas URL
Each add operation’s ref mapped to the ids of the node it created
object
object
Short id the created node answers to from now on
Created node UUID
What the transaction actually did
object
Nodes created
Update operations that changed at least one field
Edges created
Edges removed
Nodes deleted, including group members deleted with their frame
Change-detection marker of the canvas after this changeset, identical to the value the project graph endpoint reports
Operations that resolved but did not change what the caller may have expected, such as an update matching current state or a duplicate connect
Example
{ "project_id": "prj_abc123", "created": { "additionalProperty": { "id": "n9", "node_id": "7f6ae6da-4a0e-4a2f-9c6a-2c1c6b8d1f21" } }, "revision": "4f2c8ab19e3d7c05"}