Skip to content
Create a key

Paste a key to use it in the examples on these pages. The key stays in this browser tab. These pages never send it anywhere.

Restore a revision of an edit

restore_timelinePOST/v1/projects/{projectId}/timeline/restoreBeta

Brings an edit back to a revision listed by list_timeline_revisions (GET /v1/projects/{projectId}/timeline/revisions), as a new revision.

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

Send the revision to go back to and the revision you read last as expectedRevision. The edit becomes what it was at that revision, and the change is a new revision, so it can be undone the same way. A restore never costs credits: a revision that would bring back a video that is not paid for is refused, and the video can be added again with add_timeline_clip (POST /v1/projects/{projectId}/timeline/clips).

Example use

After an automatic change went wrong, a script sends the revision it found in the list and the revision it read last. The edit goes back as a new revision, so the person can undo the restore the same way.

Endpoint

Code
POST https://api.gpt-video.com/v1/projects/{projectId}/timeline/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.
  • Idempotency-Key is optional.

Parameters

Path

NameTypeRequiredDescription
projectIdstringRequiredThe project id. It starts with prj_. Matches ^prj_[0-9a-f]{20}$.

Headers

NameTypeRequiredDescription
Idempotency-KeystringOptionalSend the same key on every retry of this request. From 1 to 255 visible characters, such as a UUID. See idempotency.

Body

NameTypeRequiredDescription
revisionintegerRequiredThe revision to go back to, as list_timeline_revisions (GET /v1/projects/{projectId}/timeline/revisions) lists it. At least 0.
expectedRevisionintegerRequiredThe revision of the edit you read last, from get_timeline (GET /v1/projects/{projectId}/timeline) or from the answer of your last change. If the edit changed since then, nothing is written and the answer is CONFLICT. At least 0.

Send only the fields listed here. Any other field is refused with UNKNOWN_PARAMETER.

Request

Restore a revision of an edit.

Request example
# Create the key once. Send this same key again if you retry this request.
IDEMPOTENCY_KEY=$(uuidgen)
curl -X POST "https://api.gpt-video.com/v1/projects/prj_b9c1f9c7873dcef51a57/timeline/restore" \
  -H "Authorization: Bearer $GPT_VIDEO_API_KEY" \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "revision": 2,
    "expectedRevision": 3
  }'
// Create the key once. Send this same key again if you retry this request.
const idempotencyKey = crypto.randomUUID();
const res = await fetch("https://api.gpt-video.com/v1/projects/prj_b9c1f9c7873dcef51a57/timeline/restore", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.GPT_VIDEO_API_KEY}`,
    "Idempotency-Key": idempotencyKey,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "revision": 2,
    "expectedRevision": 3
  }),
});
const data = await res.json();
console.log(data);
import os
import uuid

import requests

# Create the key once. Send this same key again if you retry this request.
idempotency_key = str(uuid.uuid4())
r = requests.post(
    "https://api.gpt-video.com/v1/projects/prj_b9c1f9c7873dcef51a57/timeline/restore",
    headers={
        "Authorization": f"Bearer {os.environ['GPT_VIDEO_API_KEY']}",
        "Idempotency-Key": idempotency_key,
    },
    json={
        "revision": 2,
        "expectedRevision": 3
    },
)
data = r.json()
print(data)
{
  "method": "tools/call",
  "params": {
    "name": "restore_timeline",
    "arguments": {
      "projectId": "prj_b9c1f9c7873dcef51a57",
      "revision": 2,
      "expectedRevision": 3
    }
  }
}

Response

A successful call answers HTTP 200. Returns a Timeline object in timeline.

Fields to check

NameTypeDescription
timeline.idstringThe edit id. It starts with tml_.
timeline.segments[].idstringThe segment id. It starts with seg_.
timeline.texts[].idstringThe text id. It starts with ovl_.
timeline.broll[].idstringThe b-roll id. It starts with brl_.

Response example

HTTP 200
{
  "timeline": {
    "id": "tml_bbe061171a8229f8daed",
    "projectId": "prj_b9c1f9c7873dcef51a57",
    "compositionId": "cmp_cfbdd85eaaff301fa997",
    "revision": 4,
    "durationSec": 60,
    "aspect": "9:16",
    "reframe": "off",
    "captions": {
      "enabled": false,
      "style": "bold-karaoke"
    },
    "music": null,
    "fadeInSec": 0,
    "fadeOutSec": 0,
    "clips": [
      {
        "assetId": "ast_3f9a1c7e5b2d4086a1c4",
        "title": "Interview with a founder",
        "durationSec": 1800,
        "state": "ready"
      }
    ],
    "segments": [
      {
        "id": "seg_7279fbb508f4a22e65a4",
        "assetId": "ast_3f9a1c7e5b2d4086a1c4",
        "sourceStartSec": 120,
        "sourceEndSec": 150,
        "zoom": 1,
        "muted": false,
        "volume": 1,
        "outputStartSec": 0,
        "outputEndSec": 30
      },
      {
        "id": "seg_a9dcee59c1fb9edb6751",
        "assetId": "ast_3f9a1c7e5b2d4086a1c4",
        "sourceStartSec": 300,
        "sourceEndSec": 330,
        "zoom": 1,
        "muted": false,
        "volume": 1,
        "outputStartSec": 30,
        "outputEndSec": 60
      }
    ],
    "texts": [
      {
        "id": "ovl_49f5239b9cd73496225d",
        "text": "Paid before the product",
        "preset": "headline",
        "outputStartSec": 0,
        "durationSec": 3,
        "xPercent": null,
        "yPercent": null
      }
    ],
    "broll": [
      {
        "id": "brl_f44d18e008ec4009bf10",
        "assetId": "ast_8ac5d8b97546145cdbf6",
        "outputStartSec": 12,
        "durationSec": 4,
        "fit": "cover"
      }
    ],
    "diagnostics": []
  },
  "compositionId": "cmp_cfbdd85eaaff301fa997"
}
All response fields
NameTypeRequiredDescription
timelineTimeline objectRequiredDescribed in Timeline object.
compositionIdstringRequiredThe composition the edit compiles to, to export with create_export (POST /v1/compositions/{compositionId}/exports).
More examples

A revision that is not kept

POST /v1/projects/prj_b9c1f9c7873dcef51a57/timeline/restore

Request body
{
  "revision": 0,
  "expectedRevision": 1
}
HTTP 404
{
  "error": {
    "code": "NOT_FOUND",
    "message": "Revision 0 of this edit is not kept. Call list_timeline_revisions to see the ones you can restore.",
    "hint": "Check the id. An id that belongs to another account is not found either.",
    "requestId": "req_4f8c1a6e3b0d92e75a4c1f08"
  }
}

Errors

CodeStatusWhenWhat to do
NOT_FOUND404A revision that is not keptChange the request, then send it again.
CONFLICT409The project is not a Vibe Editing project, its edit is not prepared, it changed after expectedRevision, or the revision would bring back a video that is not paid for. The message says which one.Read the resource again, then decide. Do not send the same request again.
NOT_READY409See the error reference.Wait for Retry-After, then 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. A restore that would bring back a video that is not paid for is refused.

Questions

Why do I get CONFLICT with a revision number?

The edit changed after you read it: another call, the Editor Assistant or someone in the GPT-Video app wrote a new revision. Read it again with get_timeline (GET /v1/projects/{projectId}/timeline), then send your change with the revision it shows.

Why is my restore refused with a video that is not paid for?

The revision plays a video whose credits were given back, or that this edit never paid for. A restore never charges credits, so it is refused: add the video again with add_timeline_clip (POST /v1/projects/{projectId}/timeline/clips), which says the price.

View as Markdown