Edit Video

Per-scene mutations, background music, render trigger, and asset uploads, all token-gated with 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). The table uses full paths so agents can copy the endpoint without carrying hidden prefix state.

MethodEndpointPurpose
GET/v1/platform/videos/edit/:editTokenGet full video + scenes
PATCH/v1/platform/videos/edit/:editTokenUpdate video metadata (title, aspect, BGM volume, etc.)
POST/v1/platform/videos/edit/:editToken/scenesAdd a new scene
PATCH/v1/platform/videos/edit/:editToken/scenes/:sceneIdUpdate a scene's script, keywords, durations, transitions
DELETE/v1/platform/videos/edit/:editToken/scenes/:sceneIdDelete a scene
PUT/v1/platform/videos/edit/:editToken/scenes/reorderReorder scenes by ID list
POST/v1/platform/videos/edit/:editToken/scenes/:sceneId/ttsRegenerate TTS audio for a scene
POST/v1/platform/videos/edit/:editToken/scenes/:sceneId/clip/searchSearch Pexels + Pixabay for stock clips
POST/v1/platform/videos/edit/:editToken/scenes/:sceneId/clip/selectApply a selected stock clip
POST/v1/platform/videos/edit/:editToken/scenes/:sceneId/clip/uploadUpload a custom video clip (multipart)
POST/v1/platform/videos/edit/:editToken/scenes/:sceneId/visual/image/uploadUpload an image as the scene visual (multipart)
GET/v1/platform/videos/edit/:editToken/visual/slidesList slides available as visual snapshots
POST/v1/platform/videos/edit/:editToken/scenes/:sceneId/visual/slideApply a slide snapshot as the scene visual
POST/v1/platform/videos/edit/:editToken/scenes/:sceneId/visual/slide/createCreate a blank editable slide for a scene visual
POST/v1/platform/videos/edit/:editToken/scenes/:sceneId/overlays/sticker/uploadUpload a sticker overlay for the scene (multipart)
POST/v1/platform/videos/edit/:editToken/scenes/:sceneId/overlays/character/generateGenerate a character sticker overlay
POST/v1/platform/videos/edit/:editToken/sync-durationsRecompute scene durations from TTS audio buffers
POST/v1/platform/videos/edit/:editToken/thumbnailUpload a thumbnail image (multipart)
POST/v1/platform/videos/edit/:editToken/bgm/searchSearch BGM presets
POST/v1/platform/videos/edit/:editToken/bgm/selectApply a BGM preset
DELETE/v1/platform/videos/edit/:editToken/bgmRemove BGM
POST/v1/platform/videos/edit/:editToken/renderStart a Remotion render
POST/v1/platform/videos/edit/:editToken/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 /v1/platform/videos/edit/:editToken

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,
      "visualType": "image",
      "visualKey": "platform/{workspaceId}/videos/{videoId}/scenes/uuid-1/visuals/image.png",
      "visualSource": "upload",
      "remotionTemplate": "keyword",
      "keywords": ["plant", "sunlight"],
      "duration": 7.2,
      "audioOffset": 0,
      "audioDuration": 6.2,
      "videoOffset": 0,
      "videoDuration": null,
      "visualOffset": 0,
      "visualDuration": null,
      "visualFit": "cover",
      "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,
      "visualEffect": null,
      "visualMetadata": null,
      "visualAdjustments": null,
      "visualOverlays": [],
      "metadata": null
    }
  ],
  "editToken": "2dce...",
  "editTokenExpiresAt": "2026-04-25T15:15:28.628Z",
  "shareToken": "b64a..."
}

PATCH /v1/platform/videos/edit/:editToken

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
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
renderStatusstring | nullOverride render status
renderUrlstring | nullOverride rendered video URL
metadataobjectFree-form metadata

Returns the updated VideoEditResDto.


Scene Mutations

POST /v1/platform/videos/edit/:editToken/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 /v1/platform/videos/edit/:editToken/scenes/:sceneId

Update any scene field. Common fields:

FieldTypeDescription
scriptstringNew narration. Does not regenerate TTS. Call POST /v1/platform/videos/edit/:editToken/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.
visualTypestring | nullMain visual type: video, image, or slide.
visualKeystring | nullS3 key for the active visual. For slides, this is the snapshot image key.
visualSourcestring | nullVisual source: stock, upload, generated, or slide.
visualOffset / visualDurationnumberActive visual timing. Prefer these over videoOffset / videoDuration for new integrations.
visualFitstringVisual fit mode: cover or contain.
subtitleOffset / subtitleDurationnumberSubtitle timing.
subtitlesarrayOverride subtitle chunks: [{ text, offset, duration }, …].
transitionOutstring | nullTransition style.
transitionDurationnumberTransition duration in seconds.
videoEffectstring | nullnone, overlay-dark, vignette, blur, grayscale, etc.
visualEffectstring | nullGeneralized visual effect. Prefer this over videoEffect for new integrations.
visualMetadataobject | nullSource-specific metadata, such as slide id and snapshot version.
visualAdjustmentsobject | nullNon-destructive visual adjustments, such as brightness and saturation.
visualOverlaysarray | nullOrdered overlay objects drawn above the visual, such as stickers.

Returns the updated VideoSceneResDto.

DELETE /v1/platform/videos/edit/:editToken/scenes/:sceneId

Removes a scene.

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

Returns 204 No Content.

PUT /v1/platform/videos/edit/:editToken/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 /v1/platform/videos/edit/:editToken/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 /v1/platform/videos/edit/:editToken/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 /v1/platform/videos/edit/:editToken/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 /v1/platform/videos/edit/:editToken/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.


Visual Sources

The Visual source is the main image or video shown for a scene. New integrations should read visualType, visualKey, visualSource, visualOffset, visualDuration, and visualFit. Legacy videoClip* fields are still returned for compatibility.

POST /v1/platform/videos/edit/:editToken/scenes/:sceneId/visual/image/upload

Upload an image as the scene visual.

curl -X POST https://api.tutorflow.io/v1/platform/videos/edit/{editToken}/scenes/{sceneId}/visual/image/upload \
  -F "file=@diagram.png"

Returns the updated VideoSceneResDto with visualType: "image" and visualSource: "upload".

GET /v1/platform/videos/edit/:editToken/visual/slides

List slides in the same workspace that can be used as scene visuals. Only slides with thumbnails are useful for video snapshots.

curl "https://api.tutorflow.io/v1/platform/videos/edit/{editToken}/visual/slides?search=photosynthesis"

Response:

[
  {
    "id": "slide-uuid",
    "title": "Photosynthesis Overview",
    "thumbnail": "platform/{workspaceId}/slides/{slideId}/thumbnail.png",
    "contentVersion": 4,
    "editToken": "slide-edit-token"
  }
]

POST /v1/platform/videos/edit/:editToken/scenes/:sceneId/visual/slide

Apply a slide thumbnail as the scene visual.

curl -X POST https://api.tutorflow.io/v1/platform/videos/edit/{editToken}/scenes/{sceneId}/visual/slide \
  -H "Content-Type: application/json" \
  -d '{ "slideId": "slide-uuid" }'

Returns the updated VideoSceneResDto with visualType: "slide", visualSource: "slide", and slide snapshot metadata.

POST /v1/platform/videos/edit/:editToken/scenes/:sceneId/visual/slide/create

Create a blank platform slide in the same workspace and attach its edit token to the scene. Use this when your product wants a Canva-style flow where the user creates a slide from inside the video editor, edits it, then saves it back as a scene visual snapshot.

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

Response:

{
  "scene": {
    "id": "scene-uuid",
    "visualType": "slide",
    "visualKey": null,
    "visualSource": "slide",
    "visualMetadata": {
      "slideId": "slide-uuid",
      "slideEditToken": "slide-edit-token",
      "contentVersion": 1
    }
  },
  "slideId": "slide-uuid",
  "editToken": "slide-edit-token"
}

After editing the slide, capture the first slide as an image and upload it to POST /v1/platform/videos/edit/:editToken/scenes/:sceneId/visual/image/upload, then patch the scene with visualType: "slide", visualSource: "slide", and the returned visualKey.

POST /v1/platform/videos/edit/:editToken/scenes/:sceneId/overlays/sticker/upload

Upload an image sticker overlay for the scene. Stickers are stored separately from the source visual, so they can be moved, resized, and removed without changing the uploaded video, image, or slide snapshot.

curl -X POST https://api.tutorflow.io/v1/platform/videos/edit/{editToken}/scenes/{sceneId}/overlays/sticker/upload \
  -F "file=@arrow.png"

Returns the updated VideoSceneResDto with a new item in visualOverlays.

POST /v1/platform/videos/edit/:editToken/scenes/:sceneId/overlays/character/generate

Generate a character sticker overlay from a short prompt. The generated asset is stored as an overlay on the scene and returned in visualOverlays.

curl -X POST https://api.tutorflow.io/v1/platform/videos/edit/{editToken}/scenes/{sceneId}/overlays/character/generate \
  -H "Content-Type: application/json" \
  -d '{ "prompt": "friendly teacher pointing at a leaf diagram" }'
FieldTypeRequiredDescription
promptstringYesCharacter sticker prompt, 2-500 characters

Returns the updated VideoSceneResDto.


Background Music

POST /v1/platform/videos/edit/:editToken/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 /v1/platform/videos/edit/:editToken/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 /v1/platform/videos/edit/:editToken/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 /v1/platform/videos/edit/:editToken/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 /v1/platform/videos/edit/:editToken/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 /v1/platform/videos/edit/:editToken/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.