REST API
The HTTP endpoints behind the editor, for scripts and tools that don't speak MCP.
GET /api/project- current project JSONPUT /api/project- replace project JSON (body = full document). Conflict-safe: if the body'srevision≤ the revision currently on disk, the server rejects with 409 and returns{"error":"…","revision":<current>}. Append?force=1to overwrite unconditionally. Writes are atomic (tmp file + rename), so a crashed write never corrupts the file.GET /api/media- list files in ./media (name, src, size)GET /api/library?dir=sfx|elements|svg|fonts- list library assetsPOST /api/upload?name=foo.mp4- raw body saved into ./media, returns{src}. MP4/MOV/M4V uploads are auto-remuxed with+faststart(needs ffmpeg on PATH). Files copied straight into ./media by external tools skip this - remux big ones yourself (ffmpeg -i in.mp4 -c copy -movflags +faststart out.mp4) or playback stalls.POST /api/import-url- body{url:"https://…"}downloads the file into./media/and returns{src,name}(same-origin/media/…, like upload). HTTPS only; rejects localhost, private/link-local/CGNAT addresses, and redirects to those. Remote SVG is refused (/media/*.svgis served same-origin asimage/svg+xml- a scripted SVG opened as a document would run on the editor origin). Does not writeproject.json- register the media afterwards (UI andfablecut_import_mediado this). Do not put a rawhttps://URL (or another origin, includinglocalhoston a different port) inmedia.src: canvas CORS would taint the compositor and Fast / WebCodecs export cannot JPEG-encode. Import into./mediasosrcis/media/…, or serve the remote withAccess-Control-Allow-Origin.POST /api/analyze- body{src:"/media/ref.mp4", threshold?, music?}: analyze a reference video into an edit blueprint (see Remake a reference video); extracts its music into ./media.GET /api/analyze?src=…returns the cached blueprint.GET /api/events- SSE: named eventchangewhen project.json, ./media or ./library changes; named eventprofileswhenencoding-profiles.jsonchanges (UI refreshes the export-profile list only - no project reload)- Fast / WebCodecs export (browser compositor → server ffmpeg):
GET /api/export/ffmpeg→{available}·GET /api/export/profiles[?detail=1]→{default, profiles, issues}·POST /api/export/begin{fps,name,mode?,profile?,hasAudio?,pixelFormat?,width?,height?}→{id,mode,profile?,label,summary}(fpsis required - passproject.fps, no server-side default;modeis"jpeg"(default, Fast) or"annexb"(WebCodecs H.264 elementary stream); jpeg 400 ifprofileis not a defined id, or if ffmpeg rejects its args in the dry run; optionalpixelFormat:"rgba"pluswidth/heightpipes raw canvas frames instead of JPEG) ·POST /api/export/frame?id=(JPEG body for jpeg mode; raw RGBA ifbeginusedpixelFormat:"rgba"; Annex-B for annexb - one POST may concatenate frames or AUs. Must be after audio; ffmpeg is spawned on the first frame in both modes) ·POST /api/export/audio?id=(WAV body - must be sent before the first frame) ·POST /api/export/end?id=[&discard=1]→{src}under/exports/