Model APIs
Compositions and Studio export
A composition is an HTML timeline stored as a file bundle: index.html, optional sub-compositions, media files and metadata. Studio edits live in nolgia-edits.json. Rendering and editor export both use the effective timeline: authored timing plus that edit overlay.
| Method | Path | What it does |
|---|---|---|
| GET | /compositions |
List the current user's compositions, newest first. |
| POST | /compositions |
Create an empty composition. |
| GET | /compositions/{id} |
Fetch one of the current user's compositions, including its file inventory. |
| PATCH | /compositions/{id} |
Update a composition's name, description, project link, or meta. |
| DELETE | /compositions/{id} |
Delete a composition and all of its files. |
| PUT | /compositions/{id}/file |
Upload or overwrite one file in a composition. |
| DELETE | /compositions/{id}/file |
Delete one file from a composition. |
| POST | /compositions/{id}/files:signed-urls |
Mint fresh signed GET URLs for composition files and referenced platform assets. |
| POST | /compositions/{id}/clone |
Clone a composition, copying its full file bundle. |
| POST | /compositions/{id}/imports/figma |
Import a Figma frame into a composition as text layers and PNG stills. |
| POST | /compositions/{id}/render |
Queue a server-side MP4 or single-frame PNG export of the composition's effective timeline. |
| GET | /compositions/{id}/renders |
List the composition's renders, newest first (at most 20). |
| GET | /compositions/{id}/export |
Export the composition for editing in Premiere Pro, DaVinci Resolve or After Effects. |
| GET | /renders/{id} |
Fetch one render, including its status, warnings, and produced asset id. |
| POST | /renders/blocks |
Assemble ordered clip and narration pairs into one MP4. |
Render #
| Property | Value |
|---|---|
| Start | POST /compositions/{id}/render |
| Immediate response | 202 with a Render, not a generation Job |
| Poll | GET /renders/{id} |
| Statuses | queued, running, succeeded, failed |
| Default output | MP4 video asset |
| Still output | target: still produces an image/png asset |
| Result | asset_id on success; error on failure; inspect warnings either way |
Set COMPOSITION_ID to a composition you own. The request and response examples below are built from the schemas; they are not captured render runs.
curl -sS -X POST "https://api.nolgia.ai/v1/compositions/$COMPOSITION_ID/render" \
-H "Authorization: Bearer $NOLGIA_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'
{
"id": "6250ce92-d911-4b47-9f0c-a884a481586f",
"composition_id": "dcb61d59-59bc-41c1-b5cb-7b7adf22d02c",
"user_id": "4961eaef-70a6-4e9b-b746-c86ad3e62077",
"status": "queued",
"params": {},
"warnings": [],
"created_at": "2026-09-21T04:00:00Z",
"updated_at": "2026-09-21T04:00:00Z"
}
| Field | Type | Required | Description |
|---|---|---|---|
target |
RenderTarget |
No | |
still |
RenderStillOptions |
No | |
audio_mix |
AudioMix |
No | |
params |
object, nullable | No | Reserved for future render options; must be empty or omitted today. |
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | Yes | |
composition_id |
string | Yes | |
user_id |
string | Yes | |
status |
RenderStatus |
Yes | |
params |
object | Yes | Empty for a video composition render.… |
asset_id |
string, nullable | No | The produced asset, a video for an MP4 render and an image/png for a still, set when status is succeeded. |
warnings |
array of string | Yes | Human-readable notes about skipped/unsupported timeline nodes and per-block narration speed-up or last-frame hold. |
error |
string, nullable | No | Failure reason, set when status is failed (truncated to 2000 characters). |
created_at |
string | Yes | |
started_at |
string, nullable | No | |
finished_at |
string, nullable | No | |
updated_at |
string | Yes |
Save the returned id as RENDER_ID and poll until the render is terminal. A delayed worker trigger can leave it queued until the scheduled worker picks it up; keep polling the same render.
curl -sS "https://api.nolgia.ai/v1/renders/$RENDER_ID" \
-H "Authorization: Bearer $NOLGIA_TOKEN"
{
"id": "6250ce92-d911-4b47-9f0c-a884a481586f",
"composition_id": "dcb61d59-59bc-41c1-b5cb-7b7adf22d02c",
"user_id": "4961eaef-70a6-4e9b-b746-c86ad3e62077",
"status": "succeeded",
"params": {},
"asset_id": "86997121-220d-4206-a70e-64ec8474c058",
"warnings": [],
"created_at": "2026-09-21T04:00:00Z",
"started_at": "2026-09-21T04:00:02Z",
"finished_at": "2026-09-21T04:00:30Z",
"updated_at": "2026-09-21T04:00:30Z"
}
| Response field | Meaning |
|---|---|
id, composition_id, user_id |
Render, source composition and requester ids |
status |
Poll while queued or running; stop at succeeded or failed |
params |
Empty for a video composition render; records normalized still options for a still |
asset_id |
Read GET /assets/{id} for a fresh download URL; can be null if the output was later deleted |
warnings |
Notes about skipped or unsupported elements; success does not imply every timeline element was rendered |
created_at, started_at, finished_at, updated_at |
Render lifecycle timestamps |
error |
Failure reason when the render fails |
Supported output includes timed video, audio and images, Studio edit timing and track toggles, grades, masks, sampled clip motion, and supported text. Text additions use Studio textStyle; authored plain text uses the renderer's caption treatment. The API reference above describes the exact subset and its limits.
Still frames #
| Property | Value |
|---|---|
| Request | target: still plus optional still options |
| Frame selection | at_seconds or zero-based frame, never both; neither means frame 0 |
| Background | opaque by default; transparent preserves uncovered canvas alpha |
| Downscale | max_dimension from 64 to 3840 pixels |
| Resolution cap | Native still output is capped at 3840×2160; downscale larger canvases |
| Past the end | Renders the last frame and adds a warning |
curl -sS "https://api.nolgia.ai/v1/compositions/$COMPOSITION_ID/render" \
-H "Authorization: Bearer $NOLGIA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"target":"still","still":{"at_seconds":2,"background":"transparent","max_dimension":1280}}'
{
"id": "2cc38557-afc8-4dd2-8b3c-f335a36a4967",
"composition_id": "dcb61d59-59bc-41c1-b5cb-7b7adf22d02c",
"user_id": "4961eaef-70a6-4e9b-b746-c86ad3e62077",
"status": "queued",
"params": {"mode":"still","at_seconds":2,"background":"transparent","max_dimension":1280},
"warnings": [],
"created_at": "2026-09-21T04:01:00Z",
"updated_at": "2026-09-21T04:01:00Z"
}
| Response field | Meaning |
|---|---|
id, composition_id, user_id |
Render, source and requester ids, as for video |
status |
Still renders use the same asynchronous lifecycle |
params.mode |
still identifies a single-frame render |
params.at_seconds, params.background, params.max_dimension |
The normalized options the worker will apply |
warnings |
Notes about unsupported content or clamping the requested timestamp |
created_at, updated_at |
Render timestamps |
asset_id |
Appears on success and points to the PNG asset |
| Field | Type | Required | Description |
|---|---|---|---|
at_seconds |
number | No | Timestamp rounded to the nearest frame using the plan FPS in the worker, then clamped to the last frame with a warning when past the end.… |
frame |
integer | No | Zero-based frame index, clamped to the last frame with a warning when past the end. Cannot accompany at_seconds. Invalid values return 400 with "still.frame must be between 0 and 2592000". |
background |
one of opaque, transparent |
No | Opaque includes the black backdrop; omitted means opaque.… |
max_dimension |
integer | No | Downscale the finished still so its long edge is at most this many pixels, preserving aspect ratio.… |
Export #
GET /compositions/{id}/export?format=fcpxml|aejsx synchronously returns a ZIP for an editor. It uses the same effective timeline as MP4 rendering.
fcpxml #
| Property | Value |
|---|---|
| Editors | Premiere Pro and DaVinci Resolve |
| Project file | sequence.xml |
| Actual interchange | Final Cut Pro 7 XML, xmeml version 5, 30 fps |
| Text | Text additions become PNG stills under text/ |
aejsx #
| Property | Value |
|---|---|
| Editor | After Effects |
| Project file | build.jsx |
| Open | File → Scripts → Run Script File |
| Editable features | Native text layers, keyframed transforms and masks |
Both formats contain luts/*.cube, README.txt describing fidelity limits, and manifest.json. Authored HTML, CSS and GSAP animation do not map into either editor.
curl --fail-with-body -sS \
"https://api.nolgia.ai/v1/compositions/$COMPOSITION_ID/export?format=fcpxml" \
-H "Authorization: Bearer $NOLGIA_TOKEN" \
-o composition.zip
The response is 200 application/zip with an attachment disposition, not JSON. These are the documented fields in the ZIP's manifest.json:
| Manifest field | Meaning |
|---|---|
media[] |
Every referenced media file to download separately |
media[].ref |
The source media reference |
media[].asset_id |
The referenced platform asset id |
media[].path |
Destination path relative to the export folder |
media[].url |
Signed download URL, valid for one hour |
media[].expires_at |
Actual expiry of that download URL |
Export returns 404 for an unknown or foreign composition, 400 for an unknown format, 422 for a timeline without exportable clips, and 413 when its documents exceed the export limits.
Versions and Figma imports #
| Surface | What it does | Trap |
|---|---|---|
POST /compositions/{id}/clone |
Copies the full file bundle into a new composition; meta_patch shallow-merges metadata |
nolgia-edits.json is deliberately omitted so the clone starts with a clean edit overlay |
meta.series and meta.version |
Group versions; filter with GET /compositions?series=… |
Clients assign and increment versions; the API stores them verbatim |
POST /compositions/{id}/imports/figma |
Imports a frame as text-layer descriptions and PNG still assets | Returns layer descriptions without modifying the composition; the client writes its overlay |
Figma imports require a Figma PAT with file_content:read. It is used for that request only and is not stored or logged. An import supports at most 40 layers. The token belongs in the authenticated request body, never in a composition file or URL.
Share a render #
Use POST /renders/{id}/share once the render is succeeded and its output asset still exists. The link resolves to the rendered MP4; its preview uses the composition name. Read-only roles cannot share, organization members may share their own requested renders, and owners or admins may share any visible render.
curl -sS "https://api.nolgia.ai/v1/renders/$RENDER_ID/share" \
-H "Authorization: Bearer $NOLGIA_TOKEN" \
-H "Content-Type: application/json" \
-d '{"expires_in_days":30}'
This is a schema-built example; the token and URL are placeholders, not working links.
{
"id": "93b16566-1998-4fc0-8b1c-7e4c77e224ee",
"kind": "render",
"target_id": "6250ce92-d911-4b47-9f0c-a884a481586f",
"token": "…",
"token_prefix": "…",
"url": "https://nolgia.ai/share/…",
"expires_at": "2026-10-21T04:02:00Z",
"created_at": "2026-09-21T04:02:00Z",
"created_by": "4961eaef-70a6-4e9b-b746-c86ad3e62077",
"access_count": 0
}
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | Yes | |
kind |
ShareLinkKind |
Yes | |
target_id |
string | Yes | The shared asset's id, or the shared render's id. |
token |
string | No | The share token (base64url, 128 bits of entropy). Create response only. |
token_prefix |
string | Yes | The first characters of the token, for recognising a link in a listing. |
url |
string | No | The public share URL to hand out (the nolgia.ai share page). Create response only. |
expires_at |
string | No | When the link stops resolving. Absent for a link that never expires. |
has_password |
boolean | No | Viewers must enter a password. |
view_only |
boolean | No | Downloads are turned off for this link. |
created_at |
string | Yes | |
created_by |
string | Yes | The user who created the link. |
access_count |
integer | Yes | Successful public resolutions so far. |
last_accessed_at |
string | No | When the link was last resolved. Absent until the first visit. |
revoked_at |
string | No | Set once the link has been revoked. Listings only return unrevoked links. |
Save url when creating it: tokens and URLs are returned once. GET /renders/{id}/share lists active links without either secret; DELETE /renders/{id}/share/{token} accepts the share token or link id and revokes it. See File access controls for expiry, public resolution and revocation behavior.

