> ## Documentation Index
> Fetch the complete documentation index at: https://heygen-1fa696a7.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Edit Video

> Change a rendered video's script, voice, or avatar style in one call. Only the scenes you name re-render and bill, and the video keeps its video_id.

![](https://mintcdn.com/heygen-1fa696a7/hfMXXwJzjE7vBSYZ/images/theme/research-7.webp?fit=max\&auto=format\&n=hfMXXwJzjE7vBSYZ\&q=85\&s=02bcf90d74d8b9887ce224de6b8a130b)

> [!NOTE]
>
> **API reference:** [Get Video Scenes](https://heygen-1fa696a7.mintlify.site/reference/get-video-scenes.md) · [Get Video](https://heygen-1fa696a7.mintlify.site/reference/get-video.md)

`POST /v3/videos/{video_id}` edits a finished video in place. Name the scenes, script lines, and avatars to change by the ids [`GET /v3/videos/{video_id}/scenes`](https://heygen-1fa696a7.mintlify.site/reference/get-video-scenes) returns, send only the fields that change, and HeyGen renders the same `video_id` again. Scenes you leave out keep their audio and avatar footage, so a one-line fix renders and bills one scene.

<video controls playsInline preload="metadata" poster="https://dynamic.heygen.ai/image/f2934a785f03440b83cf9f65b4b78508/original.jpg">
  <source src="https://resource2.heygen.ai/video/9538146a6f514b2e8df4c22ec9409151/original.mp4" type="video/mp4" />
</video>

Before · a three-scene studio video from POST /v3/videos.

<video controls playsInline preload="metadata" poster="https://dynamic.heygen.ai/image/20fe0971fe504735b427149d9ef73f3e/original.jpg">
  <source src="https://resource2.heygen.ai/video/e0c6a0345363491aa4bafb0eaeea4d32/original.mp4" type="video/mp4" />
</video>

After · one edit call. Scene 1 has a new voice at 1.1× speed, scene 3 a new closing line. Scene 2 is the same footage.

## Three calls

**1. Read the scenes**

[`GET /v3/videos/{video_id}/scenes`](https://heygen-1fa696a7.mintlify.site/reference/get-video-scenes) on a `completed` video. It returns one `edit_version` for the video, and every scene, element, and script line with its `id`. See [Video Scenes](https://heygen-1fa696a7.mintlify.site/video-details.md#video-scenes) for the shape.

**2. Send the edit**

`POST /v3/videos/{video_id}` with the `edit_version`, the changes keyed by id, and a new UUID in the `Idempotency-Key` header. The response is `200` with `status: "pending"` and a `version_id` for the new render.

**3. Poll the video**

[`GET /v3/videos/{video_id}`](https://heygen-1fa696a7.mintlify.site/reference/get-video) until `status` is `completed`, or pass `callback_url` and `callback_id` in the edit body to get a [webhook](https://heygen-1fa696a7.mintlify.site/docs/webhooks.md). Read the scenes again for the next `edit_version` before your next edit.

## Example

The request below produced the "after" video above: a new voice on scene 1 and new text on scene 3.

```bash theme={null}
curl -X POST "https://api.heygen.com/v3/videos/9202d2d1a928090f0f7f51a1c7e35c8a" \
  -H "X-Api-Key: $HEYGEN_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "edit_version": "3c3237d23c922866e925ec7e877e87f6ac606fb03288286a37b54ab96d818c00",
    "scenes": [
      {
        "id": "scene_0_1793648761146_ie0tymo0x",
        "script": [
          {
            "id": "script_0_1793648761145_iwbuwgrse",
            "type": "text",
            "voice_id": "80b17a1be1594e578b92c0ddf4a37fc8",
            "voice_settings": { "engine_settings": { "engine_type": "starfish" }, "speed": 1.1 }
          }
        ]
      },
      {
        "id": "scene_2_1793648761146_o4iqp9ht0",
        "script": [
          {
            "id": "script_2_1793648761146_hyqywuoj9",
            "type": "text",
            "text": "Thanks for watching. Questions go to the finance channel."
          }
        ]
      }
    ]
  }'
```

```json Response theme={null}
{
  "data": {
    "video_id": "9202d2d1a928090f0f7f51a1c7e35c8a",
    "status": "pending",
    "version_id": "f1fc7f8bcc984cf1bc9dfcacc0841ee2"
  }
}
```

## What you can edit

| Edit | Fields | Rules |
| - | - | - |
| Script text | `scenes[].script[].text` | Up to 5,000 characters per line, with the same [pause tags](https://heygen-1fa696a7.mintlify.site/docs/usage-limits.md) create accepts. The line keeps its voice and the voice's language. |
| Voice | `scenes[].script[].voice_id` with `voice_settings` | A voice changes per scene: set the same `voice_id` and `voice_settings` on every text line in the scene. `voice_settings.engine_settings` is required. `speed` (`0.5`–`1.5`), `volume` (`0.0`–`1.0`), and `locale` are optional. |
| Avatar style | `scenes[].elements[]` with `type: "avatar"`: `engine`, `expressiveness`, `motion_prompt` | One engine for the whole video, so switch every avatar in one request. `engine` moves between `avatar_iv` and `avatar_v`. `motion_prompt` applies on [Avatar V](https://heygen-1fa696a7.mintlify.site/avatar-v.md) and to photo avatars on [Avatar IV](https://heygen-1fa696a7.mintlify.site/avatar-iv.md). `expressiveness` applies to photo avatars on Avatar IV. On any other avatar, either field answers `400 invalid_parameter`. |

Each line and element entry carries its `id` and its `type`, as the scenes read shows them. Omitted fields keep their value. To empty `motion_prompt` or `expressiveness`, name it in the entry's `clear` list. One request edits up to 10 scenes, so an engine switch covers videos with up to 10 avatar scenes.

Avatar style edits cover scenes with one avatar, in videos whose avatars are all photo avatars or all video avatars. Read-back fields outside the table, such as `avatar_id`, `background`, `source`, and `actions`, answer `400 edit_not_supported` with `param` naming the field. Any other key answers `400 invalid_parameter`.

```json Script text theme={null}
{
  "edit_version": "<from GET scenes>",
  "scenes": [
    {
      "id": "<scene id>",
      "script": [{ "id": "<line id>", "type": "text", "text": "Revenue grew fifteen percent this quarter." }]
    }
  ]
}
```

```json Avatar engine theme={null}
{
  "edit_version": "<from GET scenes>",
  "scenes": [
    { "id": "<scene 1 id>", "elements": [{ "id": "<avatar 1 id>", "type": "avatar", "engine": { "type": "avatar_v" } }] },
    { "id": "<scene 2 id>", "elements": [{ "id": "<avatar 2 id>", "type": "avatar", "engine": { "type": "avatar_v" } }] },
    { "id": "<scene 3 id>", "elements": [{ "id": "<avatar 3 id>", "type": "avatar", "engine": { "type": "avatar_v" } }] }
  ]
}
```

```json Motion prompt theme={null}
{
  "edit_version": "<from GET scenes>",
  "scenes": [
    {
      "id": "<scene id>",
      "elements": [
        { "id": "<avatar id>", "type": "avatar", "motion_prompt": "Nods warmly and gestures with both hands while speaking." }
      ]
    }
  ]
}
```

An engine switch keeps each scene's audio, so the video's length stays the same. An edited scene renders as it would if you had created the video with those values through [`POST /v3/videos`](https://heygen-1fa696a7.mintlify.site/studio-videos).

## Retries and versions

| Situation | Response |
| - | - |
| Same `Idempotency-Key`, same body, within 24 hours | The first response again, with the same `version_id`. One render, one charge. |
| Same `Idempotency-Key`, different body | `409 conflict`. Use a new key for a new edit. |
| Another edit while the video renders | `409 resource_not_ready`. Wait for `completed`. |
| An `edit_version` from before the last render | `409 stale_edit_version`. Read the scenes again and resend with the new version. |
| A body with only `edit_version` | Renders the video again unchanged. Scenes served from the avatar cache are free. |
| `500 internal_error` | The render may have started. Retry with the same key and the same body. |
| `503 render_not_started` | The edit is saved and its render did not start. Read the scenes for the new `edit_version`, then send only that `edit_version` with a new key. |
| Any `4xx` | Nothing is saved. Scenes, `edit_version`, and status stay as they were. |

## Billing

An edit bills as an API render of the scenes it changes, at the rate of each scene's engine. A scene drops out of the charge when every avatar in it is served from the avatar cache, which is typically the case for scenes you leave out. Scenes without an avatar bill on every render. For a three-scene video:

| Request | Scenes typically billed |
| - | - |
| New text on one line | 1 |
| New voice on scene 1, new text on scene 3 | 2 |
| Every avatar from `avatar_iv` to `avatar_v` | 3, with audio reused |
| Only `edit_version` | 0 |

## Errors

Errors use the [v3 envelope](https://heygen-1fa696a7.mintlify.site/docs/error-codes.md): `code`, `message`, and `param`, which names the field by its position in your request, for example `scenes.0.script.0.text`.

| Status | `code` | Cause |
| - | - | - |
| 400 | `invalid_parameter` | An unknown key or id, a line or element under the wrong scene, a value out of range, text over 5,000 characters, a missing or malformed `Idempotency-Key` |
| 400 | `edit_not_supported` | A read-back field outside the table above, avatars on different engines, two avatars in one scene, Avatar III, expressive or masked avatars, `more_blinking` |
| 400 | `scenes_unavailable` | The video predates the current editor format |
| 400 | `avatar_consent_required` | An avatar in the video needs [consent](https://heygen-1fa696a7.mintlify.site/docs/avatar-consent.md) before it can render |
| 400 | `video_not_editable` | A Video Agent video (edit it with [Edit Scenes](https://heygen-1fa696a7.mintlify.site/docs/edit-scenes.md)), an interactive video, or avatars and voices the workspace can no longer use |
| 402 | `insufficient_credit` | Not enough credits for the changed scenes |
| 403 | `ai_vendor_access_restricted` | The workspace's policy blocks the requested voice engine |
| 404 | `video_not_found` | No such video in your workspace |
| 409 | `resource_not_ready` | The video is rendering |
| 409 | `stale_edit_version` | The video changed after you read the scenes |
| 409 | `conflict` | The `Idempotency-Key` was used with a different body |
| 409 | `request_in_progress` | The same key is still being processed |
| 429 | `rate_limit_exceeded` | Too many requests. Retry after `Retry-After` seconds. |
| 500 | `internal_error` | The render may have started. Retry with the same key and the same body. |
| 503 | `service_unavailable` | The edit could not be applied in time. Nothing is saved; retry. |
| 503 | `render_not_started` | The edit is saved and its render did not start. Read the scenes again and send only the new `edit_version`, with a new key. |

## Edit with an agent

```text Prompt for your agent wrap theme={null}
Read https://developers.heygen.com/edit-video.md and https://developers.heygen.com/docs/for-ai-agents.md first. My HeyGen API key is in the HEYGEN_API_KEY environment variable; never ask me to paste it. Call GET /v3/videos/<VIDEO_ID>/scenes and show me each scene's script in one line. Ask me what to change. Then send one POST /v3/videos/<VIDEO_ID> with the edit_version you read, only the lines and avatars that change, and a new UUID as the Idempotency-Key. Poll GET /v3/videos/<VIDEO_ID> until completed and give me the video URL.
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.