> ## 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 — let the model pick the best moments, or cut exact timestamps you supply.

## Create a Clip Job

* Endpoint: `POST /v3/clips`
* Purpose: Start a clipping job for a source video. Returns a `clip_job_id` to poll.

### Quick Example

```bash theme={null}
curl -X POST "https://api.heygen.com/v3/clips" \
  -H "X-Api-Key: $HEYGEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "video": { "type": "url", "url": "https://example.com/interview.mp4" },
    "max_clips": 5,
    "instruction": "Pull the moments where the founder talks about pricing and growth.",
    "aspect_ratio": "9:16",
    "enable_caption": true
  }'
```

```json Response theme={null}
{
  "data": {
    "clip_job_id": "clip_abc123"
  }
}
```

### 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)). |
| `max_clips`      | integer | No       | `5`      | Maximum number of highlight clips to produce (1–10). Ignored when `windows` is supplied.                                                                                                                          |
| `instruction`    | string  | No       | —        | Editorial guidance for which moments to clip — which speaker, what topics (max 2000 chars). When omitted, the model selects highlights on its own.                                                                |
| `windows`        | array   | No       | —        | Explicit moments to cut as `[{ "start": 12.0, "end": 28.5, "label": "..." }]`. When provided, the backend cuts **exactly** these windows and skips transcription and model selection. Up to 10 windows.           |
| `aspect_ratio`   | string  | No       | `"9:16"` | Output framing: `"9:16"`, `"1:1"`, or `"16:9"`.                                                                                                                                                                   |
| `enable_caption` | boolean | No       | `false`  | Burn auto-generated captions into each clip.                                                                                                                                                                      |
| `title`          | string  | No       | —        | Display title for the job in the HeyGen dashboard.                                                                                                                                                                |
| `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.                                                                                                                                                                  |
| `folder_id`      | string  | No       | —        | Organize the resulting clips into a specific project folder.                                                                                                                                                      |

| Field         | Type   | Description                                                                                  |
| ------------- | ------ | -------------------------------------------------------------------------------------------- |
| `clip_job_id` | string | Unique identifier. Use with [`GET /v3/clips/{clip_job_id}`](#get-a-clip-job) to poll status. |

<Tip>
  Three ways to choose moments: leave `instruction` and `windows` empty for fully automatic highlight selection; add `instruction` to steer the model in plain language; or pass `windows` to cut exact timestamps with no model in the loop.
</Tip>

## Get a Clip Job

* Endpoint: `GET /v3/clips/{clip_job_id}`
* Purpose: Fetch a clip job's status and, once complete, its finished clips.

### Quick Example

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

### Path Parameters

| Parameter     | Type   | Required | Description                                              |
| ------------- | ------ | -------- | -------------------------------------------------------- |
| `clip_job_id` | string | Yes      | Unique clip-job identifier returned by `POST /v3/clips`. |

### Response

```json theme={null}
{
  "data": {
    "id": "clip_abc123",
    "title": "Founder interview",
    "status": "completed",
    "transcript_source": "auto",
    "clips": [
      {
        "id": "c_7f2e91ac",
        "label": "Why we changed our pricing",
        "url": "https://heygen-product.s3-accelerate.amazonaws.com/clips/c_7f2e91ac...mp4?X-Amz-Algorithm=...",
        "start": 142.0,
        "end": 168.4,
        "duration": 26.4,
        "aspect_ratio": "9:16",
        "score": 0.93,
        "caption_url": "https://heygen-product.s3-accelerate.amazonaws.com/clips/c_7f2e91ac...vtt?X-Amz-Algorithm=..."
      }
    ],
    "created_at": 1717000000,
    "failure_message": null
  }
}
```

### Response Fields

| Field                  | Type            | Description                                                                                 |
| ---------------------- | --------------- | ------------------------------------------------------------------------------------------- |
| `id`                   | string          | Unique clip-job identifier.                                                                 |
| `title`                | string or null  | Display title for the job.                                                                  |
| `status`               | string          | Current status: `"pending"`, `"running"`, `"completed"`, or `"failed"`.                     |
| `transcript_source`    | string or null  | How the transcript was obtained (e.g. `"auto"`). Absent when `windows` were supplied.       |
| `clips`                | array           | Finished clips. Empty until status is `"completed"`.                                        |
| `clips[].id`           | string          | Stable identifier for the clip.                                                             |
| `clips[].label`        | string          | Short human-readable title for the moment.                                                  |
| `clips[].url`          | string          | Pre-signed download URL for the clip (MP4).                                                 |
| `clips[].start`        | number          | Start time in the source video, in seconds.                                                 |
| `clips[].end`          | number          | End time in the source video, in seconds.                                                   |
| `clips[].duration`     | number          | Clip length in seconds.                                                                     |
| `clips[].aspect_ratio` | string          | Output framing of the clip.                                                                 |
| `clips[].score`        | number or null  | Model confidence that this is a strong highlight (0–1). Absent for `windows`-driven cuts.   |
| `clips[].caption_url`  | string or null  | Pre-signed URL for the clip's caption file (WebVTT). Present when `enable_caption` was set. |
| `created_at`           | integer or null | Unix timestamp of creation.                                                                 |
| `failure_message`      | string or null  | Error description. Only present when status is `"failed"`.                                  |

<Note>
  Each `url` and `caption_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/clips`
* Purpose: List clip jobs with cursor-based pagination.

### Quick Example

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

### Query Parameters

| Parameter | Type    | Required | Default | Description                                                                              |
| --------- | ------- | -------- | ------- | ---------------------------------------------------------------------------------------- |
| `limit`   | integer | No       | `10`    | Results per page (1–100).                                                                |
| `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": "clip_abc123",
      "title": "Founder interview",
      "status": "completed",
      "created_at": 1717000000
    }
  ],
  "has_more": false,
  "next_token": null
}
```

## Delete a Clip Job

* Endpoint: `DELETE /v3/clips/{clip_job_id}`
* Purpose: Permanently delete a clip job and its clips.

### Quick Example

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

### Response

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

## 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/clips/clip_abc123" \
    -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.

## 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, max_clips=5, instruction=None):
    """Start a clip job, wait for it, and return the finished clips."""
    body = {
        "video": {"type": "url", "url": video_url},
        "max_clips": max_clips,
        "aspect_ratio": "9:16",
        "enable_caption": True,
    }
    if instruction:
        body["instruction"] = instruction

    job_id = requests.post(f"{BASE}/v3/clips", headers=HEADERS, json=body).json()["data"]["clip_job_id"]

    while True:
        job = requests.get(f"{BASE}/v3/clips/{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", instruction="Best product moments"):
    print(f"{clip['label']} ({clip['duration']}s) -> {clip['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.
