---
title: "Restore a rejected clip | GPT-Video API reference"
description: "Brings a rejected clip back among the proposed clips, with the same id."
url: "https://www.gpt-video.com/developers/api/restore-clip"
operation: "restore_clip"
method: "POST"
path: "/v1/clips/{clipId}/restore"
scope: "clips:write"
---

Do not assume endpoints have parameters other than the ones explicitly specified.

# Restore a rejected clip

Operation id `restore_clip`. Request `POST /v1/clips/{clipId}/restore`.

Brings a rejected clip back among the proposed clips, with the same id.

Beta. This endpoint is supported and can gain new fields. If a change would break your code, we tell you before it takes effect and list it in the changelog.

## About

Use it to undo reject_clip (`POST /v1/clips/{clipId}/reject`): the clip goes back to status proposed, waiting for a decision. Restoring a clip that is already proposed changes nothing and answers the clip. An accepted clip cannot be restored, and the answer is CONFLICT. Works on clips of Auto Clip projects only.

## Example use

An editor who rejected a clip by mistake clicks undo in the review tool. The tool calls this, and the clip returns to the list of clips to review with the same id it had before.

## Endpoint

```text
POST https://api.gpt-video.com/v1/clips/{clipId}/restore
```

- Scope `clips:write`.
- Rate limit 60 requests a minute for each key and 120 for each account, shared by every `write` call. See [rate limits](/developers/rate-limits.md).
- `Idempotency-Key` is optional.

## Parameters

### Path

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `clipId` | string | Required | The id of the clip, as list_clips (`GET /v1/projects/{projectId}/clips`) returns it. Matches `^cnd_[0-9a-f]{20}$`. |

### Headers

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Idempotency-Key` | string | Optional | Send the same key on every retry of this request. From 1 to 255 visible characters, such as a UUID. See [idempotency](/developers/pagination-and-idempotency.md). |

## Request

Restore a rejected clip.

```bash title="curl"
curl -X POST "https://api.gpt-video.com/v1/clips/cnd_6a3d1f8e0b574c29d4e3/restore" \
  -H "Authorization: Bearer $GPT_VIDEO_API_KEY"
```

```ts title="TypeScript"
const res = await fetch("https://api.gpt-video.com/v1/clips/cnd_6a3d1f8e0b574c29d4e3/restore", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.GPT_VIDEO_API_KEY}`,
  },
});
const data = await res.json();
console.log(data);
```

```python title="Python"
import os

import requests

r = requests.post(
    "https://api.gpt-video.com/v1/clips/cnd_6a3d1f8e0b574c29d4e3/restore",
    headers={
        "Authorization": f"Bearer {os.environ['GPT_VIDEO_API_KEY']}",
    },
)
data = r.json()
print(data)
```

```json title="MCP (Full)"
{
  "method": "tools/call",
  "params": {
    "name": "restore_clip",
    "arguments": {
      "clipId": "cnd_6a3d1f8e0b574c29d4e3"
    }
  }
}
```

## Response

A successful call answers HTTP 200. Returns a [Clip object](/developers/objects.md#clip) in `clip`.

### Fields to check

| Name | Type | Description |
| --- | --- | --- |
| `clip.id` | string | The clip id. It starts with cnd_. |
| `clip.status` | string | proposed is waiting for a decision, accepted has a composition, rejected was set aside and can be restored. |

### Response example

```json title="HTTP 200"
{
  "clip": {
    "id": "cnd_6a3d1f8e0b574c29d4e3",
    "projectId": "prj_7c2e9a4f1b3d4e8096a5",
    "sourceAssetId": "ast_3f9a1c7e5b2d4086a1c4",
    "summary": "The founder explains how the first customer paid before the product existed.",
    "reason": "A clear claim in the first seconds and a result at the end.",
    "tags": [
      "startups",
      "sales"
    ],
    "createdAt": "2026-09-01T09:40:00.000Z",
    "status": "proposed",
    "rank": 2,
    "startSec": 600,
    "endSec": 640,
    "durationSec": 40,
    "title": "Team habits",
    "hook": "What our team does every morning",
    "score": 64,
    "scoreBreakdown": [
      {
        "factor": "hook",
        "label": "Hook (first 3 seconds)",
        "score": 6,
        "note": "Opens on a concrete claim."
      },
      {
        "factor": "payoff",
        "label": "Payoff / ending",
        "score": 5,
        "note": "Ends on the result."
      },
      {
        "factor": "clarity",
        "label": "Clarity",
        "score": 4,
        "note": "One idea, said plainly."
      },
      {
        "factor": "emotion",
        "label": "Emotion",
        "score": 6,
        "note": "The speaker sounds surprised."
      },
      {
        "factor": "novelty",
        "label": "Novelty / surprise",
        "score": 5,
        "note": "Not the usual advice."
      },
      {
        "factor": "selfContained",
        "label": "Self-contained",
        "score": 4,
        "note": "Needs no context."
      },
      {
        "factor": "quotability",
        "label": "Quotability",
        "score": 6,
        "note": "Has a line people repeat."
      },
      {
        "factor": "dialogue",
        "label": "Dialogue (back-and-forth)",
        "score": 5,
        "note": "A single speaker."
      }
    ],
    "transcriptExcerpt": "before we had a product and that changed everything for our team the first customer paid us before we had a product and that changed everything for our team the first customer paid us before we had a product and that changed everything for our team the first customer paid us before we had a product and that changed everything for our team the first customer paid us before we had a product and that changed everything for our team the first customer paid us before we had a product and that changed everything for our team the first customer",
    "social": {
      "title": "Team habits",
      "caption": "How a first customer paid before there was a product.",
      "hashtags": [
        "#startup",
        "#founder"
      ]
    },
    "compositionId": null
  }
}
```

**All response fields**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `clip` | Clip object | Required | Described in [Clip object](/developers/objects.md#clip). |

**More examples**

#### Restore a clip that was accepted

`POST /v1/clips/cnd_9e04a6c3d12b4f78a5b9/restore`

```json title="HTTP 409"
{
  "error": {
    "code": "CONFLICT",
    "message": "Only a rejected clip can be restored, and this clip is accepted.",
    "requestId": "req_0b4e8c2a6d1f47e3b9a5c7d2"
  }
}
```

## Errors

| Code | Status | When | What to do |
| --- | --- | --- | --- |
| [`NOT_FOUND`](/developers/errors.md#NOT_FOUND) | 404 | See the error reference. | Change the request, then send it again. |
| [`CONFLICT`](/developers/errors.md#CONFLICT) | 409 | Restore a clip that was accepted | Read the resource again, then decide. Do not send the same request again. |

Every call can also answer these errors. [`VALIDATION_FAILED`](/developers/errors.md#VALIDATION_FAILED), [`UNKNOWN_PARAMETER`](/developers/errors.md#UNKNOWN_PARAMETER), [`UNAUTHORIZED`](/developers/errors.md#UNAUTHORIZED), [`SCOPE_MISSING`](/developers/errors.md#SCOPE_MISSING), [`IDEMPOTENCY_IN_PROGRESS`](/developers/errors.md#IDEMPOTENCY_IN_PROGRESS), [`PAYLOAD_TOO_LARGE`](/developers/errors.md#PAYLOAD_TOO_LARGE), [`IDEMPOTENCY_KEY_REUSED`](/developers/errors.md#IDEMPOTENCY_KEY_REUSED), [`RATE_LIMITED`](/developers/errors.md#RATE_LIMITED), [`INTERNAL`](/developers/errors.md#INTERNAL), [`UNAVAILABLE`](/developers/errors.md#UNAVAILABLE).

## Cost

No credits are used.

## Related operations

- [`reject_clip`](/developers/api/reject-clip.md) (`POST /v1/clips/{clipId}/reject`) Reject a clip
- [`list_clips`](/developers/api/list-clips.md) (`GET /v1/projects/{projectId}/clips`) List the clips of a project

## Questions

### Does a restored clip keep its id?

Yes. Restoring only changes the status back to proposed; the id, the score and everything else stay the same.

### Can I restore a clip after the project was analyzed again?

No. A new analysis removes the rejected clips, and their ids answer NOT_FOUND. The new analysis proposes its own clips.
