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.

Frame a composition again

reframe_compositionPOST/v1/compositions/{compositionId}/reframeBeta

Computes the vertical framing of a composition again, following the face or keeping the center.

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

It starts a framing job and answers 202 with it; follow it with get_job (GET /v1/jobs/{jobId}), or read framing in get_composition (GET /v1/compositions/{compositionId}). face follows the face of the speaker, center keeps the middle of the video. When a framing job is already running on the composition, the answer is that job with reused true, and nothing new starts. Works on Auto Clip and streamer compositions; a Vibe Editing project changes its framing with the set_reframe operation of apply_timeline_operations (POST /v1/projects/{projectId}/timeline/operations). An export started while the framing runs answers NOT_READY.

Example use

A clip was framed on the center, and the speaker sits at the edge of the picture. A script asks for the face framing, follows the job with get_job (GET /v1/jobs/{jobId}), and exports the clip again when the job is done.

Endpoint

Code
POST https://api.gpt-video.com/v1/compositions/{compositionId}/reframe
  • 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.
  • It starts work that runs on its own. The answer comes back before the work is done.

Parameters

Path

NameTypeRequiredDescription
compositionIdstringRequiredThe id of the composition: accept_clip (POST /v1/clips/{clipId}/accept) returns it for a clip, and list_compositions (GET /v1/projects/{projectId}/compositions) or the project's compositionId give it for the other kinds of project. Matches ^cmp_[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
modestringRequiredface follows the face of the speaker, center keeps the middle of the video. One of face, center.

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

Request

Follow the face.

Request example
curl -X POST "https://api.gpt-video.com/v1/compositions/cmp_4e8c2a6f09d14b73a1e5/reframe" \
  -H "Authorization: Bearer $GPT_VIDEO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "face"
  }'
const res = await fetch("https://api.gpt-video.com/v1/compositions/cmp_4e8c2a6f09d14b73a1e5/reframe", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.GPT_VIDEO_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "mode": "face"
  }),
});
const data = await res.json();
console.log(data);
import os

import requests

r = requests.post(
    "https://api.gpt-video.com/v1/compositions/cmp_4e8c2a6f09d14b73a1e5/reframe",
    headers={
        "Authorization": f"Bearer {os.environ['GPT_VIDEO_API_KEY']}",
    },
    json={
        "mode": "face"
    },
)
data = r.json()
print(data)
{
  "method": "tools/call",
  "params": {
    "name": "reframe_composition",
    "arguments": {
      "compositionId": "cmp_4e8c2a6f09d14b73a1e5",
      "mode": "face"
    }
  }
}

Response

A successful call answers HTTP 202. Returns a Job object in job.

Fields to check

NameTypeDescription
job.idstringThe job id. It starts with job_.
job.statusstringqueued and running are still working; done, failed and cancelled are final.
reusedbooleantrue when a framing job was already running on the composition and this is that job.

Response example

  • Location: https://api.gpt-video.com/v1/jobs/job_4e8a2c6f0b3d49a7e1c5
HTTP 202
{
  "job": {
    "id": "job_4e8a2c6f0b3d49a7e1c5",
    "kind": "framing",
    "status": "queued",
    "progress": 0,
    "errorMessage": null,
    "projectId": "prj_7c2e9a4f1b3d4e8096a5",
    "compositionId": "cmp_4e8c2a6f09d14b73a1e5",
    "exportId": null,
    "assetId": null,
    "toolRunId": null,
    "turnId": null,
    "createdAt": "2026-09-01T11:10:00.000Z",
    "startedAt": null,
    "finishedAt": null
  },
  "reused": false
}
All response fields
NameTypeRequiredDescription
jobJob objectRequiredDescribed in Job object.
reusedbooleanRequiredtrue when a framing job was already running on the composition and this is that job.
More examples

A framing that is already running

POST /v1/compositions/cmp_4e8c2a6f09d14b73a1e5/reframe

Request body
{
  "mode": "center"
}
  • Location: https://api.gpt-video.com/v1/jobs/job_4e8a2c6f0b3d49a7e1c5
HTTP 202
{
  "job": {
    "id": "job_4e8a2c6f0b3d49a7e1c5",
    "kind": "framing",
    "status": "queued",
    "progress": 0,
    "errorMessage": null,
    "projectId": "prj_7c2e9a4f1b3d4e8096a5",
    "compositionId": "cmp_4e8c2a6f09d14b73a1e5",
    "exportId": null,
    "assetId": null,
    "toolRunId": null,
    "turnId": null,
    "createdAt": "2026-09-01T11:10:00.000Z",
    "startedAt": null,
    "finishedAt": null
  },
  "reused": true
}

A composition of a Vibe Editing project

POST /v1/compositions/cmp_cfbdd85eaaff301fa997/reframe

Request body
{
  "mode": "face"
}
HTTP 409
{
  "error": {
    "code": "CONFLICT",
    "message": "Only Auto Clip and streamer compositions follow a face. For a Vibe Editing project use the set_reframe operation.",
    "requestId": "req_2b7d5f9a1c3e46b0d8a2c4e6"
  }
}

Frame a composition that does not exist

POST /v1/compositions/cmp_7a1f5d3c9e0b42d8f6a2/reframe

Request body
{
  "mode": "face"
}
HTTP 404
{
  "error": {
    "code": "NOT_FOUND",
    "message": "Composition cmp_7a1f5d3c9e0b42d8f6a2 not found",
    "hint": "Check the id. An id that belongs to another account is not found either.",
    "requestId": "req_6b2d9f0e4a7c41b3d8e5a2f9"
  }
}

Errors

CodeStatusWhenWhat to do
NOT_FOUND404Frame a composition that does not existChange the request, then send it again.
CONFLICT409A composition of a Vibe Editing projectRead 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.

  • get_job (GET /v1/jobs/{jobId}) Get a job
  • get_composition (GET /v1/compositions/{compositionId}) Get a composition
  • create_export (POST /v1/compositions/{compositionId}/exports) Export a composition
  • edit_composition (POST /v1/compositions/{compositionId}/edit) Edit a composition

Questions

Does a trim keep the framing?

No. A trim made with edit_composition (POST /v1/compositions/{compositionId}/edit) clears the face framing, because it was computed for the old start; when the project follows the face, a framing job starts again by itself, and get_composition (GET /v1/compositions/{compositionId}) shows it as tracking.

Why did I get a job that was started earlier?

A framing job was already running on the composition, so the answer is that job with reused true. Wait for it with get_job (GET /v1/jobs/{jobId}), then ask again if you want the other mode.

View as Markdown