Restore a rejected clip
restore_clipPOST/v1/clips/{clipId}/restoreBeta
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
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
writecall. See rate limits. Idempotency-Keyis 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. |
Request
Restore a rejected clip.
curl -X POST "https://api.gpt-video.com/v1/clips/cnd_6a3d1f8e0b574c29d4e3/restore" \
-H "Authorization: Bearer $GPT_VIDEO_API_KEY"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);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){
"method": "tools/call",
"params": {
"name": "restore_clip",
"arguments": {
"clipId": "cnd_6a3d1f8e0b574c29d4e3"
}
}
}Response
A successful call answers HTTP 200. Returns a Clip object 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
{
"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. |
More examples
Restore a clip that was accepted
POST /v1/clips/cnd_9e04a6c3d12b4f78a5b9/restore
{
"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 | 404 | See the error reference. | Change the request, then send it again. |
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, UNKNOWN_PARAMETER, UNAUTHORIZED, SCOPE_MISSING, IDEMPOTENCY_IN_PROGRESS, PAYLOAD_TOO_LARGE, IDEMPOTENCY_KEY_REUSED, RATE_LIMITED, INTERNAL, UNAVAILABLE.
Cost
No credits are used.
Related operations
reject_clip(POST /v1/clips/{clipId}/reject) Reject a cliplist_clips(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.