> ## 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.

# AI clipping

> Turn a long-form video into short, ready-to-share highlight clips with the HeyGen AI Clipping API — the model picks the best moments, cuts them to your target durations, and scores each clip's virality.

<img className="w-full h-44 object-cover rounded-xl" src="https://mintcdn.com/heygen-1fa696a7/hfMXXwJzjE7vBSYZ/images/theme/research-5.webp?fit=max&auto=format&n=hfMXXwJzjE7vBSYZ&q=85&s=422da140ece4b799d490f85bb2013ca5" alt="" noZoom width="1400" height="788" data-path="images/theme/research-5.webp" />

## Create a Clip Job

* Endpoint: [`POST /v3/ai-clipping`](/reference/create-ai-clipping)
* Purpose: Start a clipping job for a source video. Returns an `ai_clipping_id` to poll.

### Quick Example

```bash theme={null}
curl -X POST "https://api.heygen.com/v3/ai-clipping" \
  -H "X-Api-Key: $HEYGEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "video": { "type": "url", "url": "https://example.com/interview.mp4" },
    "title": "Founder interview",
    "output_settings": {
      "duration_types": ["30", "60"],
      "aspect_ratio": "portrait",
      "captions": false,
      "prompt": "Pull the moments where the founder talks about pricing and growth."
    }
  }'
```

```json Response theme={null}
{
  "data": {
    "ai_clipping_id": "edf8d2c44ba441b89f395072b3ef7e34"
  }
}
```

### Request Body

| Parameter         | Type   | Required | Default     | Description                                                                                                                                                                                                       |
| ----------------- | ------ | -------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `video`           | object | Yes      | —           | Source video. Provide as `{ "type": "url", "url": "https://..." }` or `{ "type": "asset_id", "asset_id": "..." }` (from [`POST /v3/assets`](/reference/upload-asset) — see [Upload Assets](/docs/upload-assets)). |
| `title`           | string | No       | —           | Title for the job. Defaults to the source video's title when omitted.                                                                                                                                             |
| `input_language`  | string | No       | auto-detect | ISO-639-1 source language code (e.g. `en`, `es`). Omit to auto-detect.                                                                                                                                            |
| `output_settings` | object | No       | —           | Configuration for the produced clips — see [Output settings](#output-settings).                                                                                                                                   |
| `callback_url`    | string | No       | —           | [Webhook](/docs/webhooks) URL — receives a POST when the job completes or fails.                                                                                                                                  |
| `callback_id`     | string | No       | —           | Arbitrary ID echoed back in the webhook payload.                                                                                                                                                                  |

### Output settings

| Field            | Type             | Required | Default    | Description                                                                                                                                     |
| ---------------- | ---------------- | -------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `duration_types` | array of strings | No       | —          | Target clip durations to produce: `"30"`, `"60"`, `"180"`, or `"long"` (1–4 entries). Each duration produces a separate clip.                   |
| `aspect_ratio`   | string           | No       | `portrait` | Framing for all produced clips: `portrait` (9:16, social-ready), `landscape` (16:9), or `square` (1:1).                                         |
| `captions`       | boolean          | No       | `true`     | Captions are burned into the clips by default. Set `false` for clean, caption-free footage — as in the example above.                           |
| `caption_style`  | string           | No       | —          | Named caption style preset (e.g. `classic`, `bold`) when captions are on. Omit for the default style.                                           |
| `prompt`         | string           | No       | —          | Editorial guidance for the highlight model — which speaker, what topics (max 500 chars). When omitted, the model selects highlights on its own. |

<Tip>
  Want captions on some clips and clean footage on others? Captions are a per-job setting, so submit two jobs from the same source `video` — one with `"captions": false` — and pick per platform. To style burned-in captions on other footage, `caption_style` presets like `classic` and `bold` keep the look consistent.
</Tip>

## Get a Clip Job

* Endpoint: [`GET /v3/ai-clipping/{job_id}`](/reference/get-ai-clipping)
* Purpose: Fetch a clip job's live status and, as they render, its finished clips.

### Quick Example

```bash theme={null}
curl -X GET "https://api.heygen.com/v3/ai-clipping/edf8d2c44ba441b89f395072b3ef7e34" \
  -H "X-Api-Key: $HEYGEN_API_KEY"
```

### Path Parameters

| Parameter | Type   | Required | Description                                                                   |
| --------- | ------ | -------- | ----------------------------------------------------------------------------- |
| `job_id`  | string | Yes      | Unique job identifier returned by `POST /v3/ai-clipping` as `ai_clipping_id`. |

### Response

```json theme={null}
{
  "data": {
    "id": "edf8d2c44ba441b89f395072b3ef7e34",
    "title": "Founder interview",
    "status": "completed",
    "input_language": "en",
    "source_duration": 1264.4,
    "progress": 100,
    "clips": [
      {
        "id": "92799db89cdf444eb40a3d3db4378f4c",
        "status": "completed",
        "title": "Why we changed our pricing",
        "duration_seconds": 26.4,
        "aspect_ratio": "portrait",
        "virality_score": 65,
        "thumbnail_url": "https://resource2.heygen.ai/video_repurpose/.../1280x720.jpeg",
        "video_url": "https://resource2.heygen.ai/video_repurpose/.../1280x720.mp4?..."
      }
    ],
    "created_at": 1784649990
  }
}
```

### Response Fields

| Field                      | Type            | Description                                                                          |
| -------------------------- | --------------- | ------------------------------------------------------------------------------------ |
| `id`                       | string          | Unique job identifier.                                                               |
| `title`                    | string or null  | Display title for the job.                                                           |
| `status`                   | string          | Job lifecycle status: `pending`, `running`, `completed`, `failed`, or `cancelled`.   |
| `input_language`           | string or null  | Detected or supplied source language code.                                           |
| `source_duration`          | number or null  | Duration of the source video in seconds.                                             |
| `progress`                 | integer         | Approximate progress (0–100). `100` when all clips are completed.                    |
| `clips`                    | array           | Produced clips. Populates as each clip renders — empty until the first one finishes. |
| `clips[].id`               | string          | Unique clip identifier.                                                              |
| `clips[].status`           | string          | Per-clip status: `pending`, `completed`, or `failed`.                                |
| `clips[].title`            | string or null  | Model-generated clip title.                                                          |
| `clips[].duration_seconds` | number or null  | Final clip length in seconds. Populated when the clip completes.                     |
| `clips[].aspect_ratio`     | string or null  | Framing of the finished clip.                                                        |
| `clips[].virality_score`   | integer or null | Model-predicted virality score (0–100).                                              |
| `clips[].thumbnail_url`    | string or null  | Pre-signed thumbnail URL.                                                            |
| `clips[].video_url`        | string or null  | Pre-signed MP4 download URL.                                                         |
| `callback_id`              | string or null  | Client-provided callback ID.                                                         |
| `created_at`               | integer         | Unix timestamp (seconds) of job creation.                                            |
| `failure_message`          | string or null  | Error description. Only present when status is `failed`.                             |

<Note>
  Each `video_url` and `thumbnail_url` is a pre-signed link with a limited lifetime. Download the file (or hand the URL to a downstream step) soon after the job completes rather than caching it for later.
</Note>

## List Clip Jobs

* Endpoint: [`GET /v3/ai-clipping`](/reference/list-ai-clipping)
* Purpose: List clip jobs with cursor-based pagination.

### Quick Example

```bash theme={null}
curl -X GET "https://api.heygen.com/v3/ai-clipping?limit=10" \
  -H "X-Api-Key: $HEYGEN_API_KEY"
```

### Query Parameters

| Parameter | Type    | Required | Default | Description                                                                              |
| --------- | ------- | -------- | ------- | ---------------------------------------------------------------------------------------- |
| `limit`   | integer | No       | `10`    | Results per page.                                                                        |
| `token`   | string  | No       | —       | Opaque cursor token. Pass the `next_token` from a prior response to fetch the next page. |

### Response

```json theme={null}
{
  "data": [
    {
      "id": "edf8d2c44ba441b89f395072b3ef7e34",
      "title": "Founder interview",
      "status": "completed",
      "progress": 100,
      "created_at": 1784649990
    }
  ],
  "has_more": false,
  "next_token": null
}
```

The list endpoint reports coarse `progress`; poll [`GET /v3/ai-clipping/{job_id}`](#get-a-clip-job) for live in-flight progress on a specific job.

## Delete a Clip Job

* Endpoint: [`DELETE /v3/ai-clipping/{job_id}`](/reference/delete-ai-clipping)
* Purpose: Permanently delete a clip job and its clips.

### Quick Example

```bash theme={null}
curl -X DELETE "https://api.heygen.com/v3/ai-clipping/edf8d2c44ba441b89f395072b3ef7e34" \
  -H "X-Api-Key: $HEYGEN_API_KEY"
```

### Response

```json theme={null}
{
  "data": {
    "id": "edf8d2c44ba441b89f395072b3ef7e34"
  }
}
```

## Polling Pattern

Clip jobs are processed asynchronously. Poll until status reaches `completed` or `failed`.

Status transitions: `pending` → `running` → `completed` | `failed`

```bash theme={null}
while true; do
  STATUS=$(curl -s "https://api.heygen.com/v3/ai-clipping/$JOB_ID" \
    -H "X-Api-Key: $HEYGEN_API_KEY" | jq -r '.data.status')
  echo "Status: $STATUS"
  [ "$STATUS" = "completed" ] || [ "$STATUS" = "failed" ] && break
  sleep 10
done
```

For long recordings, prefer a [`callback_url`](/docs/webhooks) over tight polling — HeyGen will POST you the finished job instead (`ai_clipping.success` / `ai_clipping.fail` [webhook events](/docs/webhook-events)).

## Asset Inputs

The `video` field accepts two input formats:

**By URL** — any publicly accessible HTTPS link:

```json theme={null}
{ "type": "url", "url": "https://example.com/recording.mp4" }
```

**By asset ID** — reference a file previously uploaded via [`POST /v3/assets`](/reference/upload-asset) (see [Upload Assets](/docs/upload-assets)):

```json theme={null}
{ "type": "asset_id", "asset_id": "asset_xyz789" }
```

## Full Example

```python theme={null}
import time
import requests

API_KEY = "YOUR_API_KEY"
BASE = "https://api.heygen.com"
HEADERS = {"x-api-key": API_KEY, "Content-Type": "application/json"}


def clip_video(video_url, prompt=None):
    """Start a clip job, wait for it, and return the finished clips."""
    body = {
        "video": {"type": "url", "url": video_url},
        "output_settings": {
            "duration_types": ["30", "60"],
            "aspect_ratio": "portrait",
            "captions": False,
        },
    }
    if prompt:
        body["output_settings"]["prompt"] = prompt

    job_id = requests.post(
        f"{BASE}/v3/ai-clipping", headers=HEADERS, json=body
    ).json()["data"]["ai_clipping_id"]

    while True:
        job = requests.get(f"{BASE}/v3/ai-clipping/{job_id}", headers=HEADERS).json()["data"]
        if job["status"] in ("completed", "failed"):
            break
        time.sleep(10)

    if job["status"] == "failed":
        raise RuntimeError(job.get("failure_message") or "clip job failed")
    return job["clips"]


for clip in clip_video("https://example.com/interview.mp4", prompt="Best product moments"):
    print(f"{clip['title']} ({clip['duration_seconds']}s) -> {clip['video_url']}")
```

Pairing clips with audio? The same [Tools](/background-music) suite covers [background music](/background-music) and [sound effects](/sound-effects) to score your cuts.
