# Clip a video

> Analyze the link, create the submission, follow the states and work with the clips the AI generated.

Clipping has three resources: the **video** (the source), the **submission** (one processing run of that video) and the **clips** (the cuts the submission generated). A video can have several submissions, for example with different sections or templates.

```text
POST /clips/info  →  POST /clips  →  GET .../submissions/{id}  →  GET .../clips
   analysis          submission         until completed             the cuts
```

## Analyze the link

```bash
curl -X POST https://api.cut.pro/api/v1/clips/info \
  -H "X-Api-Key: $CUTPRO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ" }'
```

The response carries the title, author, platform, duration in seconds, thumbnail and the cost in credits. Analyzing does not charge, but it has its own limit of 10 per minute. If you have the file, use the [upload](/en/uploads) in place of this step.

When the link does not work, the `code` says why:

| Status | Codes | Means |
|---|---|---|
| `400` | `VIDEO_TOO_LONG` | Exceeds the plan's maximum duration. `extra.duration` and `extra.max_duration` say by how much. |
| `403` | `PRIVATE_VIDEO`, `AGE_RESTRICTED`, `ACCESS_DENIED`, `REGION_BLOCKED`, `COPYRIGHT_BLOCKED`, `PLATFORM_NOT_SUPPORTED` | The platform does not deliver this video. |
| `404` | `VIDEO_ID_NOT_FOUND`, `UNAVAILABLE`, `METADATA_UNAVAILABLE` | The video does not exist or was taken down. |
| `422` | `PLAYLIST_URL`, `CHANNEL_URL`, `SHORTS_NOT_SUPPORTED`, `LIVE_STREAM`, `PREMIUM_ONLY`, `AUDIO_ONLY`, `INVALID_URL`, `INVALID_DURATION`, `INVALID_DIMENSIONS` | The link is valid, but it is not a video that can be clipped. |

## Create the submission

```bash
curl -X POST https://api.cut.pro/api/v1/clips \
  -H "X-Api-Key: $CUTPRO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "video_id": "7412908365112823",
    "source_language": "pt",
    "timeframe": { "start": 600, "end": 1800 },
    "template_id": "7398110254410021"
  }'
```

| Field | Required | Description |
|---|---|---|
| `video_id` | yes | The `id` from `POST /clips/info` or from the upload. |
| `source_language` | no | `auto` (default), `pt` or `en`. Set it when you know: it is more accurate. |
| `timeframe` | no | `{ start, end }` in seconds. Clips only that section. |
| `template_id` | no | A template from `GET /templates`. Every clip comes out edited with it, ready to render. |
| `translate_to` | no | ISO 639-1 code (`en`, `es`). Translates the clips' captions and costs more. |
| `strategy_id` | no | A clipping strategy saved in Cut.Pro. Without it, the AI uses the default configuration. |

> Credits are charged on creation. `credits_charged` in the response says how much was charged.

Common errors on creation: `402 INSUFFICIENT_CREDITS`, `409 VIDEO_ALREADY_PROCESSING` (the same video is already processing), `429 TOO_MANY_PENDING_CLIPS` (workspace queue full), `400 TIMEFRAME_OUT_OF_BOUNDS` and `400 TIMEFRAME_TOO_SHORT`.

## Follow the submission

```bash
curl https://api.cut.pro/api/v1/clips/7412908365112823/submissions/7412908371004912 \
  -H "X-Api-Key: $CUTPRO_API_KEY"
```

Poll every 5 to 10 seconds. The states follow this order:

| `status` | What is happening |
|---|---|
| `queued` | In the queue. `queue_position` and `estimated_time` (in seconds) say how long is left. |
| `downloading` | Downloading the source. |
| `transcribing` | Transcribing the audio. |
| `video_analysis` | Analyzing the image. |
| `analyzing` | The AI is choosing the moments. |
| `finalizing` | Generating the clips. |
| `completed` | Done. `clips_count` says how many clips came out. |
| `failed` | Failed. The reason is in `error_code`. |

### A source that is not live yet

A submission can stop at `downloading` because the source does not fully exist yet: a scheduled premiere, a live stream still on air or a recording the platform is still processing. In that case `waiting_reason` is filled in:

| `waiting_reason` | Means |
|---|---|
| `SOURCE_PREMIERE_SCHEDULED` | Scheduled premiere. `waiting_until` carries the announced time, when the platform provides it. |
| `SOURCE_LIVE_IN_PROGRESS` | The live stream is still on air. |
| `SOURCE_VOD_PROCESSING` | The broadcast ended and the platform is still preparing the recording. |

It is not an error and it is not stuck: the submission continues on its own when the source becomes available. Show this to the person and offer to cancel, because `DELETE` in this state returns the credits.

### When it fails

`error_code` says the reason. Those that start with `DOWNLOAD_` come from the source (`DOWNLOAD_PRIVATE_VIDEO`, `DOWNLOAD_MEMBERS_ONLY`, `DOWNLOAD_GEO_RESTRICTED`, `DOWNLOAD_REMOVED_BY_UPLOADER`): switching to another video is the way out. `EMPTY_TRANSCRIPT` and `DOWNLOAD_NO_AUDIO` say there is no speech to clip. The rest are processing failures and are worth another attempt:

```bash
curl -X POST https://api.cut.pro/api/v1/clips/7412908365112823/submissions/7412908371004912/retry \
  -H "X-Api-Key: $CUTPRO_API_KEY"
```

The retry creates a **new** submission with the same settings and charges like `POST /clips`. The one that failed stays in the history. It only works for a submission in `failed`: for the others, the response is `409 SUBMISSION_NOT_FAILED`.

## List the clips

```bash
curl "https://api.cut.pro/api/v1/clips/7412908365112823/submissions/7412908371004912/clips?min_rating=7&sort=rating&order=desc" \
  -H "X-Api-Key: $CUTPRO_API_KEY"
```

```json title="200 OK"
{
  "clips": [
    {
      "id": "7412908412887301",
      "title": "The chorus everyone knows",
      "description": "The highest-energy moment of the video, with the audience singing along.",
      "rating": 9.2,
      "start_time": 42.5,
      "end_time": 71.0,
      "language": "en",
      "created_at": "2026-10-29T18:04:50.000Z",
      "thumbnail_url": "https://...",
      "download_url": "https://...",
      "play_url": "https://...",
      "has_template_applied": false,
      "edit_id": null
    }
  ],
  "pagination": { "current_page": 1, "total_pages": 1, "total_count": 6, "has_next_page": false, "has_previous_page": false, "limit": 20 }
}
```

- `rating` goes from 0 to 10. Filter with `min_rating` and `max_rating`.
- Sort by `rating`, `duration`, `title` or `start_time`.
- `download_url` is the raw cut, with no editing. For the MP4 with template and captions, [render it](/en/rendering).
- The links are signed and short-lived. Ask for the list again when you are going to use it.

### Clip captions

```bash
curl "https://api.cut.pro/api/v1/clips/7412908365112823/submissions/7412908371004912/clips/7412908412887301/subtitles?format=srt" \
  -H "X-Api-Key: $CUTPRO_API_KEY"
```

Returns SRT or plain text (`format=txt`), with time starting at `00:00` and aligned to the clip. If the clip has an edit, the captions are the edit's, with corrections and translation.

## Retention

A submission's clips do not stay forever. Once retention passes, the submission shows `expired: true` and the clip routes respond `410 SUBMISSION_EXPIRED`. It is permanent: do not retry, upload the video again. What you already rendered is still recoverable by the `edit_id`.

## Organize the library

| Route | What it does |
|---|---|
| `GET /clips` | Lists the videos, with counters for clips, edits, exports and posts and the state of the last submission. |
| `GET /clips/{videoId}/submissions` | Lists a video's submissions, with `credit_cost`, `timeframe` and `expired`. |
| `DELETE /clips/{videoId}/submissions/{submissionId}` | Deletes the submission and the clips. If it is still processing, it cancels and returns the credits. |
| `DELETE /clips/{videoId}/submissions/{submissionId}/clips/{clipId}` | Deletes one clip. |
| `DELETE /clips/{videoId}` | Deletes the video with all its submissions. Those processing are canceled and refunded. |

Deleting cannot be undone.
