Edit Video

Per-scene mutations, background music, render trigger, and asset uploads — all token-gated, no API key required.

Edit-Token Endpoints

Once you have an editToken from Create Video, the following endpoints are reachable without an API key (the token is the auth). All paths are prefixed with /v1/platform/videos/edit/:editToken.

MethodPathPurpose
GET/Get full video + scenes
PATCH/Update video metadata (title, aspect, BGM volume, etc.)
POST/scenesAdd a new scene
PATCH/scenes/:sceneIdUpdate a scene's script, keywords, durations, transitions
DELETE/scenes/:sceneIdDelete a scene
PUT/scenes/reorderReorder scenes by ID list
POST/scenes/:sceneId/ttsRegenerate TTS audio for a scene
POST/scenes/:sceneId/clip/searchSearch Pexels + Pixabay for stock clips
POST/scenes/:sceneId/clip/selectApply a selected stock clip
POST/scenes/:sceneId/clip/uploadUpload a custom video clip (multipart)
POST/sync-durationsRecompute scene durations from TTS audio buffers
POST/thumbnailUpload a thumbnail image (multipart)
POST/bgm/searchSearch BGM presets
POST/bgm/selectApply a BGM preset
DELETE/bgmRemove BGM
POST/renderStart a Remotion render
POST/render/cancelCancel an in-progress render

The token rotates on demand only — it does not rotate on read. Each GET extends editTokenExpiresAt by 1 hour from now (sliding window), so any URL you've already shared keeps working as long as someone uses it.


GET /

Returns the full video including all scenes.

curl https://api.tutorflow.io/v1/platform/videos/edit/{editToken}

Returns a VideoEditResDto:

{
  "videoRequestId": "e41a085a-e43f-4f63-92f4-9e11250f6e63",
  "platformVideoId": "e10b8286-94ad-4139-a946-3548b46f6d07",
  "title": "What Is Photosynthesis for Kids?",
  "description": null,
  "aspectRatio": "16:9",
  "visibility": "PRIVATE",
  "renderStatus": "IDLE",
  "videoKey": null,
  "thumbnailKey": null,
  "bgmAudioKey": null,
  "bgmVolume": 0.15,
  "bgmOffset": 0,
  "userNarrationScript": null,
  "slug": "what-is-photosynthesis-for-kids-d6a02f3b",
  "metadata": { "language": "en", "sceneCount": 4, "targetDurationSeconds": 30 },
  "scenes": [
    {
      "id": "uuid-1",
      "order": 0,
      "script": "Photosynthesis is how plants make their own food…",
      "displayText": null,
      "ttsAudioKey": "platform/{workspaceId}/videos/{videoId}/scenes/uuid-1/tts.mp3",
      "videoClipKey": null,
      "videoClipSource": null,
      "remotionTemplate": "keyword",
      "keywords": ["plant", "sunlight"],
      "duration": 7.2,
      "audioOffset": 0,
      "audioDuration": 6.2,
      "videoOffset": 0,
      "videoDuration": null,
      "subtitleOffset": 0,
      "subtitleDuration": 6.2,
      "subtitles": [{ "text": "Photosynthesis is how plants make their own food", "offset": 0, "duration": 3.1 }],
      "transitionOut": null,
      "transitionDuration": 1,
      "videoEffect": null,
      "metadata": null
    }
  ],
  "editToken": "2dce...",
  "editTokenExpiresAt": "2026-04-25T15:15:28.628Z",
  "shareToken": "b64a..."
}

PATCH /

Update video-level metadata.

curl -X PATCH https://api.tutorflow.io/v1/platform/videos/edit/{editToken} \
  -H "Content-Type: application/json" \
  -d '{ "title": "Updated Title", "aspectRatio": "9:16", "bgmVolume": 0.2 }'
FieldTypeDescription
titlestringUpdated title
descriptionstring | nullUpdated description
aspectRatiostring16:9, 9:16, or 1:1
visibilitystringPUBLIC or PRIVATE
bgmAudioKeystring | nullS3 key for custom BGM (use bgm/select for presets)
bgmVolumenumber0.0–1.0
bgmOffsetnumberSeconds into BGM track to start
userNarrationScriptstring | nullManual narration override
videoKeystring | nullOverride the rendered mp4 key
thumbnailKeystring | nullOverride the thumbnail key
metadataobjectFree-form metadata

Returns the updated VideoEditResDto.


Scene Mutations

POST /scenes

Add a scene at the end (or at a specific order).

curl -X POST https://api.tutorflow.io/v1/platform/videos/edit/{editToken}/scenes \
  -H "Content-Type: application/json" \
  -d '{
    "script": "And that is how the carbon cycle returns oxygen to the atmosphere.",
    "duration": 6,
    "keywords": ["forest", "atmosphere"],
    "remotionTemplate": "keyword"
  }'
FieldTypeRequiredDescription
scriptstringYesNarration text. Used for TTS and subtitle generation.
ordernumberNoPosition in the scene list (0-indexed). Defaults to end.
displayTextstringNoOn-screen text overlay (for title/quote templates).
remotionTemplatestringNokeyword, title, quote, or none. Defaults to keyword.
keywordsstring[]NoUsed for clip search and overlay.
durationnumberNoScene duration in seconds. Auto-computed from TTS if omitted.
transitionOutstringNoTransition to the next scene: fade, slide, wipe.

Returns the created VideoSceneResDto.

PATCH /scenes/:sceneId

Update any scene field. Common fields:

FieldTypeDescription
scriptstringNew narration. Does not regenerate TTS — call POST /scenes/:sceneId/tts after.
displayTextstring | nullOn-screen overlay text.
keywordsstring[]Keywords for clip search / overlay.
remotionTemplatestringkeyword, title, quote, or none.
durationnumberScene duration in seconds.
audioOffset / audioDurationnumberTTS clip timing within the scene.
videoOffset / videoDurationnumberStock clip timing.
subtitleOffset / subtitleDurationnumberSubtitle timing.
subtitlesarrayOverride subtitle chunks: [{ text, offset, duration }, …].
transitionOutstring | nullTransition style.
transitionDurationnumberTransition duration in seconds.
videoEffectstring | nullnone, overlay-dark, vignette, blur, grayscale, etc.

Returns the updated VideoSceneResDto.

DELETE /scenes/:sceneId

Removes a scene.

curl -X DELETE https://api.tutorflow.io/v1/platform/videos/edit/{editToken}/scenes/{sceneId}

Returns 204 No Content.

PUT /scenes/reorder

Replace the scene order in a single call.

curl -X PUT https://api.tutorflow.io/v1/platform/videos/edit/{editToken}/scenes/reorder \
  -H "Content-Type: application/json" \
  -d '{ "sceneIds": ["uuid-3", "uuid-1", "uuid-2", "uuid-4"] }'

Returns the updated VideoEditResDto.


TTS

POST /scenes/:sceneId/tts

Regenerate the TTS audio for a single scene. Use after editing the scene's script. Re-distributes subtitle timing based on the new audio length.

curl -X POST https://api.tutorflow.io/v1/platform/videos/edit/{editToken}/scenes/{sceneId}/tts

Returns the updated VideoSceneResDto with the new ttsAudioKey, audioDuration, subtitleDuration, and subtitles.


Stock Clips

POST /scenes/:sceneId/clip/search

Search Pexels + Pixabay for matching stock clips. Returns interleaved results so the UI shows variety.

curl -X POST https://api.tutorflow.io/v1/platform/videos/edit/{editToken}/scenes/{sceneId}/clip/search \
  -H "Content-Type: application/json" \
  -d '{ "keyword": "sunlight on leaves" }'

Response:

[
  { "source": "pexels",  "sourceId": 7845321, "thumbnailUrl": "...", "previewUrl": "...mp4", "duration": 12 },
  { "source": "pixabay", "sourceId": 142398,  "thumbnailUrl": "...", "previewUrl": "...mp4", "duration": 8 }
]

POST /scenes/:sceneId/clip/select

Apply a selected clip. The server downloads the clip from previewUrl and re-uploads it to the workspace's S3 path.

curl -X POST https://api.tutorflow.io/v1/platform/videos/edit/{editToken}/scenes/{sceneId}/clip/select \
  -H "Content-Type: application/json" \
  -d '{
    "source": "pexels",
    "sourceId": 7845321,
    "previewUrl": "https://videos.pexels.com/.../clip.mp4"
  }'

Returns the updated VideoSceneResDto with the new videoClipKey.

POST /scenes/:sceneId/clip/upload

Upload your own clip as multipart/form-data.

curl -X POST https://api.tutorflow.io/v1/platform/videos/edit/{editToken}/scenes/{sceneId}/clip/upload \
  -F "file=@my-clip.mp4"

Returns the updated VideoSceneResDto.


Background Music

POST /bgm/search

Search the BGM preset library.

curl -X POST https://api.tutorflow.io/v1/platform/videos/edit/{editToken}/bgm/search \
  -H "Content-Type: application/json" \
  -d '{ "keyword": "uplifting" }'

Response:

[
  { "id": "preset-001", "title": "Sunny Acoustic", "tags": ["uplifting", "warm"], "durationSeconds": 142, "s3Key": "..." }
]

Pass keyword: "" (or omit) to list all presets.

POST /bgm/select

curl -X POST https://api.tutorflow.io/v1/platform/videos/edit/{editToken}/bgm/select \
  -H "Content-Type: application/json" \
  -d '{ "presetId": "preset-001" }'

Returns the updated VideoEditResDto with bgmAudioKey set and metadata populated with bgmTitle and bgmPresetId.

DELETE /bgm

curl -X DELETE https://api.tutorflow.io/v1/platform/videos/edit/{editToken}/bgm

Clears bgmAudioKey and removes bgmTitle / bgmPresetId from metadata.


Sync Durations

After editing scripts or replacing TTS audio, run sync-durations to recompute scene durations from the actual audio buffers. This is normally automatic but can be useful after bulk edits.

curl -X POST https://api.tutorflow.io/v1/platform/videos/edit/{editToken}/sync-durations

Response:

{ "updated": 3 }

Thumbnail

POST /thumbnail

Upload a thumbnail image as multipart/form-data.

curl -X POST https://api.tutorflow.io/v1/platform/videos/edit/{editToken}/thumbnail \
  -F "file=@thumb.jpg"

Returns the updated VideoEditResDto with thumbnailKey set.


Render

POST /render

Start a Remotion render. The Lambda runs asynchronously and updates renderStatus via callback. Pre-sets videoKey to where the mp4 will land.

curl -X POST https://api.tutorflow.io/v1/platform/videos/edit/{editToken}/render

Returns the updated VideoEditResDto:

{
  "renderStatus": "RENDERING",
  "videoKey": "platform/{workspaceId}/videos/{videoId}/rendered/photosynthesis-1dvr.mp4",
  "...": "..."
}

Poll GET /v1/platform/videos/edit/:editToken until renderStatus is COMPLETED or FAILED. Typical render time: 1–3 minutes.

POST /render/cancel

Reset a stuck or unwanted render to IDLE. The Lambda may still finish in the background, but its callback is ignored.

curl -X POST https://api.tutorflow.io/v1/platform/videos/edit/{editToken}/render/cancel

Returns the updated VideoEditResDto.