Apply one operation to a project's composition
Required permission: projects:write
API key auth. Prefix cf_live_ for production orgs, cf_test_ for sandbox.
In: header
Path Parameters
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
One scoped composition operation. Discriminated by type — clip.add / clip.remove / clip.update patch clips across any family; the rest cover markers, reframe, effects, captions, format, tracks, and the server-authoritative ripple recomputes. Every variant is .strict(): an unknown field is refused, not ignored.
Author a scene shot and place it on a dedicated overlay track. The host validates the scene, generates and registers an immutable wrapper component source, and emits the ordinary track/clip operations carrying props.componentRef — you edit a scene SPEC, never wrapper TSX or a source hash. Registration and the composition update are ONE undoable edit; a failure publishes nothing and leaves no clip pointing at an unresolved source. Pass EXACTLY ONE of trackId (an existing dedicated scene track) or newTrack: true (mint one). That track holds scene-shot clips and gaps only — no generic component/primitive/media clips in v1 — and existing generic overlay tracks are unaffected. Scene clips use front zPlane and full-frame placement: outer per-clip region, position, scale, rotation, fit, effects, animate, params.transition, params.sequenceGroup and internal fadeIn/fadeOut are REFUSED with a path, because the shot's own layer transforms are the single transform owner. TEXT: space: "screen" text is composed above the world result, stays fixed in the frame and stays sharp through focus; space: "world" text is rasterized into the 3D scene, moves with the camera and is occluded by geometry. Screenshots and world text are UNLIT and colour-managed so product UI colours are not tinted by the studio lighting, while device bodies are lit and cast shadows; an unlit surface still occludes. SCOPE GAP (pre-existing, neither closed nor changed by scene shots): global wrap effects — composition-level grades and camera effects — do not reach front-overlay clips, so they do not affect a scene shot. Author the look INSIDE the shot (post.grain, post.vignette, post.focus, backdrop, environment) instead. DISCOVERY: there is no built-in scene primitive to look up in list_catalog; the wrapper this operation registers appears afterwards as an ordinary INSTALLED component under the existing catalog rules. ASSETS: assets binds each slot name a layer references to a media id in the same project, and the slot's declared KIND decides what it admits — an image slot takes PNG, JPEG or WebP, a video slot MP4 or WebM. Binding the wrong kind is refused with the slot's path.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/v1/projects/string/composition/ops" \ -H "Content-Type: application/json" \ -d '{ "type": "scene.add", "clipId": "string", "startTime": 0, "duration": 1, "scene": { "version": 2, "referenceSize": { "width": 16, "height": 16 }, "layers": [ { "kind": "group", "id": "string", "children": [ { "kind": "group", "id": "string", "children": [] } ] } ] }, "assets": { "property1": "string", "property2": "string" } }'{ "error": { "code": "string", "message": "string", "contract": "string", "contractVersion": "string", "details": { "property1": null, "property2": null } }}{ "error": { "code": "string", "message": "string", "contract": "string", "contractVersion": "string", "details": { "property1": null, "property2": null } }}{ "x402Version": 2, "accepts": [ {} ], "error": "string"}{ "error": { "code": "string", "message": "string", "contract": "string", "contractVersion": "string", "details": { "property1": null, "property2": null } }}{ "error": { "code": "string", "message": "string", "contract": "string", "contractVersion": "string", "details": { "property1": null, "property2": null } }}{ "error": { "code": "string", "message": "string", "contract": "string", "contractVersion": "string", "details": { "property1": null, "property2": null } }}{ "error": { "code": "string", "message": "string", "contract": "string", "contractVersion": "string", "details": { "property1": null, "property2": null } }}{ "error": { "code": "string", "message": "string", "contract": "string", "contractVersion": "string", "details": { "property1": null, "property2": null } }}{ "error": { "code": "string", "message": "string", "contract": "string", "contractVersion": "string", "details": { "property1": null, "property2": null } }}Apply a batch of operations to a project's composition (or dry-run validate) POST
Atomically applies an array of CompositionOps. All ops succeed or none do (transactional). Pass `if_match` for optimistic-concurrency control (409 stale_etag on mismatch). Pass `dry_run: true` to validate the batch — runs the same apply + projection accept/reject guards WITHOUT persisting, returning `{ valid, errors }` with `locator.op_index` on the first failing op. Both modes may carry `warnings[]` — non-fatal authoring advisories (e.g. a card whose html reads a CSS custom property no token defines). Warnings never block.
Delete a composition DELETE
Delete a composition and its version history. REFUSES the project's ACTIVE composition (409 composition_active) — make another one active first, or delete the project.