Land a composition you authored
Put a composition the caller authored onto a scene's element — the other end of GET /scenes/{sceneId}/authoring-context.
It goes through the SAME path a generated composition takes: the real validation gate stack at its live configuration, then namespacing, per-instance CSS scoping, theme-variable injection, asset-slot expansion and hosting. Authored work is not a second-class route.
Timing, theme resolution, text-fit geometry and camera authority belong to the pipeline: author against the values the authoring context returns rather than hard-coding equivalents.
A refusal answers 422 carrying the gate's own verdict, so dry_run: true is free and worth doing first. Expect refusals for a requestAnimationFrame or wall-clock drive (the renderer seeks a paused timeline and never runs one), a <canvas> in the DOM path, an unclosed <template>, no registered timeline, or nodes appended to document.body.
Refuses a scene that is mid-generation rather than racing its write-back (409), and refuses if the scene changed while the composition was in flight (409) — re-read and retry. Free unless the HTML declares generated assets; any cost is reported.
Advisory claims: the response carries claimed_by when another actor holds a live claim on the scene (POST /scenes/{sceneId}/claim). The write is never blocked by a claim.
Authorization
bearerAuth Typecut API key. Generate one in app.typecut.ai → Settings → API keys. Send as Authorization: Bearer tc_live_….
In: header
Path Parameters
uuidRequest Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X PUT "https://example.com/scenes/497f6eca-6276-4993-bfeb-53cbbbba6f08/composition" \ -H "Content-Type: application/json" \ -d '{ "html": "string" }'{
"data": {
"sceneId": "string",
"elementId": "string",
"htmlUrl": "string",
"previousUrl": "string",
"applied": true,
"resolved": true,
"validation": {
"property1": null,
"property2": null
},
"mountedAs": {
"property1": null,
"property2": null
},
"apiCost": 0,
"claimed_by": {
"kind": "human",
"label": "string",
"since": "string",
"expires_at": "string",
"expires_in_s": 0,
"note": "string"
}
}
}{
"error": {
"type": "string",
"code": "string",
"message": "string"
}
}{
"error": {
"type": "string",
"code": "string",
"message": "string"
}
}{
"error": {
"type": "string",
"code": "string",
"message": "string"
}
}{
"error": {
"type": "string",
"code": "string",
"message": "string"
}
}{
"error": {
"type": "string",
"code": "string",
"message": "string"
}
}{
"error": {
"type": "string",
"code": "string",
"message": "string"
}
}{
"error": {
"type": "string",
"code": "string",
"message": "string"
}
}Render real frames of this scene POST
Real pixel frames, exactly as the final MP4 shows them: the same document, on the same GPU renderer, through the same capture pipeline.
Say you are working on a scene (advisory claim) POST
Take, or renew, an ADVISORY time-limited claim on a scene: a lock the editor shows and other writers see as claimed_by on their scene writes.