Compositor (compv3) headless contract
Drive the free compv3 compositor over the API: node config shape, layers, stage size and the rendered PNG output.
The compositor (compv3) renders layered images/text/shapes to a single PNG at a
fixed canvas ("stage") size. Rendering is free (no AI credits) and returns a
durable cdn.wireflow.ai URL. This page is the contract for driving it via the API.
Node config shape
The canonical location is node.data.config:
{
"nodeType": "compv3",
"config": {
"stage": { "width": 1080, "height": 1350 }, // canvas size in px
"layerOrder": ["bg", "headline", "logo"], // back-to-front draw order
"layers": {
"bg": { "type": "image", "x": 0, "y": 0, "width": 1080, "height": 1350, "fit": "cover" },
"headline": { "type": "text", "text": "HEADLINE", "x": 70, "y": 900, "width": 940, "fill": "#fff", "fontFamily": "Anton", "fontSize": 120 },
"logo": { "type": "image", "x": 820, "y": 60, "width": 180, "height": 180, "fit": "contain" }
}
}
}
Layer types: image, text, rectangle, gradient, draw. The editor-state
shape data: { stage, layers, layerOrder } is also accepted, but config.* is
canonical — author there.
Binding: a layer receives dynamic content by key (no {{tokens}}). An
incoming edge whose target handle is the layer key, or a value under that key in
the data batch port / inputs, overrides the layer: a string sets .text for a
text layer or .url for an image layer.
Image fit modes (sizing to the layer box)
Every image layer with an explicit width and height is scaled to that box:
fit |
behavior |
|---|---|
cover |
fill the box, crop overflow (preserves aspect) |
contain |
fit inside the box, letterboxed (preserves aspect) |
fill / stretch |
stretch to the box exactly (ignores aspect) |
| (unset, sized layer) | defaults to contain — honors the box, never overflows |
| (unset, no box) | native size (full-bleed) |
Set
fitexplicitly when you want crop (cover) or stretch (fill). A sized layer with nofitnow scales into its box (previously it drew at the source's natural resolution and could overflow the layout).
Setting an input:image node's media via the API
You do not need a human to drag-and-drop. Set the URL in the node's config
when you create/PUT the workflow — any of these fields works (first present wins):
imageUrl, image, mediaUrl, videoUrl, url.
{ "nodeType": "input:image", "config": { "imageUrl": "https://cdn.wireflow.ai/your-asset.png" } }
The node then resolves as an upstream media source for downstream nodes (compositor layers, generators, etc.) headlessly.
Headless preview (true export, no billed run)
Render a compositor to a PNG at stage resolution without running the workflow:
POST /api/v1/workflows/:id/compositor/preview
Authorization: Bearer <API_KEY> # scope: workflows:read
{
"nodeId": "comp", // optional — defaults to the first compv3
"inputs": { "bg": "https://…/photo.png" }, // optional per-layer-key port values
"layers": { … }, // optional — override the saved layout
"layerOrder": ["bg","headline"], // optional
"stage": { "width": 1080, "height": 1350 }// optional — override the canvas size
}
→ 200 { "data": { "nodeId", "url", "width", "height", "inputsHash", "warnings?", "failedImages?", "failedFonts?" } }
Use it to iterate on a layout and see the real output before committing or
running the graph. The returned url is a durable CDN PNG. Empty body previews the
node exactly as saved.
Discovering the contract programmatically
GET /api/v1/workflows/:id/schema returns a compositors[] array describing each
compv3 node: nodeId, label, stage, the layers (key + type + whether
AI-bindable), and where the output image lands. Call it instead of reverse-engineering.
Notes
- A compositor's output is cached and reused on re-run only while its inputs and stage size are unchanged — a stage resize re-renders at the new size.
- Normalization re-adds a canonical
layer_1input port to compv3 nodes (a defensive default to avoid dangling edges); an empty one is harmless — just leave it or wire/override the keys you use.