Promoat.Partner API

Videos

Video edits

Change a finished video without starting over: redo one scene, rewrite a line, or replace the whole soundtrack. Every edit makes a new video — the original stays untouched, so it is always your undo.

Shared rules

  • Edits work on finished videos made with the current engines (partner_h3t_ / partner_h3v_ / partner_se_ / partner_fs_ jobs — an edit can be edited again). Older videos return 409 VIDEO_NOT_EDITABLE. The job status says editable: true when a video qualifies.
  • Each edit is an async job with its own workflow_id (partner_se_… for fix-scene and edit-script, partner_fs_… for fix-sound) and source_workflow_id pointing at the original. Poll it like any video.
  • An Idempotency-Key header (or client_request_id) is required (400 IDEMPOTENCY_KEY_REQUIRED) unless you send dry_run: true.
  • dry_run: true returns the quote and changes nothing. expected_credits works as on /videos: a higher server quote → 409 QUOTE_MISMATCH.
  • One open edit per source video at a time (409 EDIT_IN_PROGRESS, within 30 minutes).
  • Unknown body fields are rejected with 400 INVALID_BODY on fix-scene and edit-script. fix-sound ignores them, so check the spelling of expected_credits and dry_run there.
  • The quote is reserved up front and is a ceiling, exactly like a new video.

See the scenes

GET/api/partner/v1/videos/{workflow_id}/scenes

Free. Lists the scenes you can target by scene_index.

Request
curl https://platform.promoat.ai/api/partner/v1/videos/partner_h3t_8f2c…/scenes \
  -H "Authorization: Bearer $PROMOAT_KEY"
200 OK
{
  "workflow_id": "partner_h3t_8f2c…",
  "video_type": "talking_head",
  "resolution": "768P",
  "editable": true,
  "voice": { "source": "ai_voice" },
  "scenes": [
    { "index": 0, "line": "Hi! Three quick updates from the shop.", "seconds": 8,
      "start_seconds": 0, "talks": true, "clip_url": "https://…", "poster_url": "https://…" },
    { "index": 1, "line": "First, we extended our opening hours.", "seconds": 7,
      "start_seconds": 8, "talks": true }
  ]
}

video_type is talking_head or moving_scene; voice.source is ai_voice, recording or none. Errors: 404, 409 VIDEO_NOT_READY, 409 VIDEO_NOT_EDITABLE.

Fix a scene

POST/api/partner/v1/videos/{workflow_id}/fix-scene
FieldTypeDescription
scene_indexint 0–99 requiredWhich scene to redo.
descriptionstring ≤500Talking head: omit for a new take of the same frame; describe a change for a new frame for that scene (adds an image). Scenes: required (400 FIX_TEXT_REQUIRED).
expected_creditsint ≥0Optional price lock.
dry_runbooleanQuote only.
Request — a new take of scene 0
curl -X POST https://platform.promoat.ai/api/partner/v1/videos/partner_h3t_8f2c…/fix-scene \
  -H "Authorization: Bearer $PROMOAT_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: fix-4812-scene0-v1" \
  -d '{ "scene_index": 0, "expected_credits": 64 }'
200 OK
{
  "workflow_id": "partner_se_3b91…",
  "status": "queued",
  "credits_reserved": 64,
  "credits_quoted": 64,
  "job_type": "scene_edit_video",
  "source_workflow_id": "partner_h3t_8f2c…",
  "scene_indices": [0],
  "edit_kind": "new_take",
  "price_table_version": "2026-09-30",
  "duplicate": false
}

edit_kind is new_take, new_frame or visual_fix (scenes). A dry run returns { dry_run: true, credits_quoted, credits_required, credits_balance, sufficient_credits, lines, clips, source_workflow_id, scene_indices, edit_kind, price_table_version }. Also 400 INVALID_SCENE (no such scene) and 400 FIX_TEXT_REQUIRED.

Rewrite lines

POST/api/partner/v1/videos/{workflow_id}/edit-script

{ "lines": [{ "scene_index": 1, "line": "…≤600 chars" }] }— 1 to 20 lines. The new lines are spoken in the video's own voice, so this works only for videos voiced by an AI voice. edit_kind is edit_script.

Request
curl -X POST https://platform.promoat.ai/api/partner/v1/videos/partner_h3t_8f2c…/edit-script \
  -H "Authorization: Bearer $PROMOAT_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: edit-4812-v2" \
  -d '{ "lines": [{ "scene_index": 1, "line": "First, we now open at 7 every morning." }] }'

# → { "workflow_id": "partner_se_…", "status": "queued", "credits_reserved": …, "credits_quoted": …,
#     "job_type": "scene_edit_video", "source_workflow_id": "partner_h3t_8f2c…",
#     "scene_indices": [1], "edit_kind": "edit_script",
#     "price_table_version": "2026-09-30", "duplicate": false }

Add "dry_run": true to see credits_quoted first; only the rewritten scenes are made again.

ErrorWhen
400 EMPTY_LINEA line is blank.
400 LINE_TOO_LONGThe line is too long for its scene; the body includes max_words.
400 VOICE_EDIT_UNAVAILABLEThe video was voiced by your own recording, is silent, or its sound was replaced with fix-sound.
400 NO_CHANGESEvery line matches what is already there.

Replace the sound

POST/api/partner/v1/videos/{workflow_id}/fix-sound

Send exactly one new take:

  • { "audio_url": "https://…" } — a recording;
  • { "tts_asset_id": "…" } — one of your tts_audio assets;
  • { "voice_id", "script" (≤4000), "voice_settings"?, "language"? } — new speech.

If the source is a scene video in which no scene speaks on camera and the new take is within ±300 ms of its length, the sound is swapped for free (plan swap_audio). Otherwise the video is made again at the take's length (plan regenerate, paid).

A paid fix-sound requires expected_credits

For a regenerate plan you must send expected_credits at least equal to the price, or you get 409 { "error": "QUOTE_MISMATCH", "code": "quote_mismatch", credits_quoted, plan }. Call with dry_run: true first.

1. Dry run → the quote
curl -X POST https://platform.promoat.ai/api/partner/v1/videos/partner_h3t_8f2c…/fix-sound \
  -H "Authorization: Bearer $PROMOAT_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "audio_url": "https://your-cdn.com/audio/new-take-15s.mp3", "dry_run": true }'

# → { "dry_run": true, "source_workflow_id": "partner_h3t_8f2c…", "plan": "regenerate",
#     "credits_quoted": 121, "lines": [ … ], "video_ms": 15000,
#     "price_table_version": "2026-09-30" }
2. Queue with the quote and a key
curl -X POST https://platform.promoat.ai/api/partner/v1/videos/partner_h3t_8f2c…/fix-sound \
  -H "Authorization: Bearer $PROMOAT_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: fix-sound-4812-1" \
  -d '{ "audio_url": "https://your-cdn.com/audio/new-take-15s.mp3", "expected_credits": 121 }'

# → { "workflow_id": "partner_fs_…", "status": "queued", "plan": "regenerate",
#     "credits_reserved": 121, "credits_quoted": 121,
#     "source_workflow_id": "partner_h3t_8f2c…", "job_type": "fix_sound_video",
#     "price_table_version": "2026-09-30", "duplicate": false }

Errors: 400 TAKE_TOO_SHORT / 400 TAKE_TOO_LONG ({ code, message, video_ms }), 422 INVALID_URL(the take can't be read).

What edits cost

EditLinesTotal
Fix scene — new take of an 8 s talking-head scene (768P)generation 6464
Fix scene — with a description (new frame)generation 64 + first_frame 468
Fix sound — new 15 s take on a talking head (768P)generation 120 + transcription 1121
Fix sound — scene video, no on-camera talking, take within ±300 ms—free

Errors common to all edits

StatuserrorMeaning
404NOT_FOUNDNo such video on your account.
409VIDEO_NOT_READYThe source video has not finished.
409VIDEO_NOT_EDITABLEMade with the previous engines, or otherwise not editable.
409EDIT_IN_PROGRESSAnother edit of this video is still open.
409QUOTE_MISMATCHThe quote is above expected_credits.
400IDEMPOTENCY_KEY_REQUIREDNo key and not a dry run.
402INSUFFICIENT_CREDITSBalance below the quote.
429TOO_MANY_ACTIVE_JOBSConcurrent job cap hit.
503TRY_AGAINBriefly unavailable; nothing charged — retry with the same key.

More on codes and retries in Errors & limits.

Try it

Try itGET/api/partner/v1/videos/{workflow_id}/scenesfree
Add your API key in the sidebar to enable this.
Try itPOST/api/partner/v1/videos/{workflow_id}/fix-scenefree
Add your API key in the sidebar to enable this.