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.

Export a composition

create_exportPOST/v1/compositions/{compositionId}/exportsBeta

Starts rendering a composition to an MP4 file and returns the export to follow.

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

Call this when a composition is ready to become a video file. It answers 202 at once with the export, queued, and a Location to follow; read it with get_export (GET /v1/exports/{exportId}) (with ?wait= to hold the request) until it is done, then download the file from its downloadUrl. The export renders the composition as it is when its render starts: a change saved while it waits in the queue is in the file, and a change saved after that is not. Once it is done, its revision says which revision the file holds. Every composition can be exported: of an Auto Clip clip, of a split screen, streamer, Reddit story or fake text project, or of a Vibe Editing edit. A composition that uses a file the API cannot use (one the GPT-Video app put in it) is refused before anything is used. An account that is not on the Creator or Studio plan exports through the API bonus, which pays for exports up to a fixed length (see the FAQ); a longer one answers PLAN_REQUIRED. paidWith says who paid this request. While the face framing of the clip is still being computed the call answers NOT_READY: wait the seconds in Retry-After and send it again. Asking again while the same revision is exporting returns that export and uses nothing. Always send an Idempotency-Key, the same one on every retry: a retry of the same request never uses a second export, and if the first try stopped before the render started, the retry starts it, with the composition as it is at the retry. This answer never carries a download link; get_export does.

Example use

A team that posts to YouTube Shorts accepts the clips it likes, calls create_export (POST /v1/compositions/{compositionId}/exports) for each composition with its own Idempotency-Key, and follows every export with get_export (GET /v1/exports/{exportId}) until its file is ready.

Endpoint

Code
POST https://api.gpt-video.com/v1/compositions/{compositionId}/exports
  • Scope spend.
  • Rate limit 10 requests a minute for each key and 20 for each account, shared by every spend call. See rate limits.
  • Idempotency-Key is required.
  • It starts work that runs on its own. The answer comes back before the work is done.

Parameters

Path

NameTypeRequiredDescription
compositionIdstringRequiredThe composition to export, as accept_clip (POST /v1/clips/{clipId}/accept) or get_composition (GET /v1/compositions/{compositionId}) returned it. It starts with cmp_. Matches ^cmp_[0-9a-f]{20}$.

Headers

NameTypeRequiredDescription
Idempotency-KeystringRequiredThis operation spends, so the key is required. Create it once, before the request, and send the same key on every retry. From 1 to 255 visible characters, such as a UUID. See idempotency.

Request

Export a composition.

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/compositions/cmp_4e8c2a6f09d14b73a1e5/exports" \
  -H "Authorization: Bearer $GPT_VIDEO_API_KEY" \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY"
// 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/compositions/cmp_4e8c2a6f09d14b73a1e5/exports", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.GPT_VIDEO_API_KEY}`,
    "Idempotency-Key": idempotencyKey,
  },
});
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/compositions/cmp_4e8c2a6f09d14b73a1e5/exports",
    headers={
        "Authorization": f"Bearer {os.environ['GPT_VIDEO_API_KEY']}",
        "Idempotency-Key": idempotency_key,
    },
)
data = r.json()
print(data)
{
  "method": "tools/call",
  "params": {
    "name": "create_export",
    "arguments": {
      "compositionId": "cmp_4e8c2a6f09d14b73a1e5",
      "confirm": true,
      "idempotencyKey": "REPLACE-WITH-A-NEW-UUID-FOR-THIS-CALL"
    }
  }
}

Response

A successful call answers HTTP 202. Returns a Export object in export.

Fields to check

NameTypeDescription
export.idstringThe export id. It starts with rnd_.
export.jobIdstring or nullThe job that renders this export, to read with get_job (GET /v1/jobs/{jobId}). It starts with job_; null while the export has no job yet.
export.statusstringqueued and rendering are still working; done, failed and cancelled are final.
export.downloadUrlstring or nullA link that downloads the MP4 with no API key, for 15 minutes and for this file only. Only get_export (GET /v1/exports/{exportId}) and list_exports (GET /v1/projects/{projectId}/exports) give one, once the export is done and while the file is kept; every read gives a new link. create_export (POST /v1/compositions/{compositionId}/exports) always answers null.
export.downloadUrlExpiresAtstring or nullWhen downloadUrl stops working; null when there is no link.
paidWithstring or nullWho paid for this request: plan is the credits or the daily allowance of the account's plan, api_bonus is the API bonus. null when this request paid nothing, because the same work was already running. A retry with the same Idempotency-Key says who paid the first time.

Response example

  • Location: https://api.gpt-video.com/v1/exports/rnd_6d0f2a8c4e1b47a9c3f5
HTTP 202
{
  "export": {
    "id": "rnd_6d0f2a8c4e1b47a9c3f5",
    "compositionId": "cmp_4e8c2a6f09d14b73a1e5",
    "projectId": "prj_7c2e9a4f1b3d4e8096a5",
    "jobId": "job_8c3f1e5a9d2b4f7c06e1",
    "revision": 0,
    "status": "queued",
    "progress": 0,
    "errorMessage": null,
    "createdAt": "2026-09-01T11:00:00.000Z",
    "finishedAt": null,
    "file": null,
    "downloadUrl": null,
    "downloadUrlExpiresAt": null,
    "fileDeletesAt": null,
    "fileDeletedAt": null
  },
  "paidWith": "plan"
}
All response fields
NameTypeRequiredDescription
exportExport objectRequiredDescribed in Export object.
paidWithstring or nullRequiredWho paid for this request: plan is the credits or the daily allowance of the account's plan, api_bonus is the API bonus. null when this request paid nothing, because the same work was already running. A retry with the same Idempotency-Key says who paid the first time. One of plan, api_bonus.
More examples

The framing of the clip is still being computed

POST /v1/compositions/cmp_4e8c2a6f09d14b73a1e5/exports

  • Retry-After: 10
HTTP 409
{
  "error": {
    "code": "NOT_READY",
    "message": "The framing of this clip is still being computed. The export can start once it is done.",
    "hint": "Wait the number of seconds in the Retry-After header, then send the same request again.",
    "requestId": "req_5c2e8a1f0b7d4e6a9c3f8b21"
  }
}

Export a split screen video

POST /v1/compositions/cmp_cc26cb47fd6004aa5fba/exports

  • Location: https://api.gpt-video.com/v1/exports/rnd_2f9b4e7c1a3d58e06b2c
HTTP 202
{
  "export": {
    "id": "rnd_2f9b4e7c1a3d58e06b2c",
    "compositionId": "cmp_cc26cb47fd6004aa5fba",
    "projectId": "prj_9cf6ba9cd17fd89cf513",
    "jobId": "job_5d1a8e3f0c6b49a27e5d",
    "revision": 0,
    "status": "queued",
    "progress": 0,
    "errorMessage": null,
    "createdAt": "2026-09-01T11:20:00.000Z",
    "finishedAt": null,
    "file": null,
    "downloadUrl": null,
    "downloadUrlExpiresAt": null,
    "fileDeletesAt": null,
    "fileDeletedAt": null
  },
  "paidWith": "plan"
}

A composition that uses a file the API cannot use

POST /v1/compositions/cmp_4e8c2a6f09d14b73a1e5/exports

HTTP 409
{
  "error": {
    "code": "CONFLICT",
    "message": "This composition uses a file that cannot be used through the API. Remove it in the GPT-Video app, then export again.",
    "requestId": "req_0d6f3b9e2a5c8f1b4e7a0c36"
  }
}

An export longer than the API bonus pays for

POST /v1/compositions/cmp_cc26cb47fd6004aa5fba/exports

HTTP 402
{
  "error": {
    "code": "PLAN_REQUIRED",
    "message": "This composition is 30 minutes long, and the API bonus pays for exports of up to 10 minutes. Choose a Creator or Studio plan to export it.",
    "hint": "The API bonus pays first. When it cannot, choose a Creator or Studio plan at https://www.gpt-video.com/app/billing.",
    "requestId": "req_3c8e1b6f9a2d47e05b8c1f63"
  }
}

The exports of the day are used up

POST /v1/compositions/cmp_4e8c2a6f09d14b73a1e5/exports

HTTP 429
{
  "error": {
    "code": "DAILY_LIMIT_REACHED",
    "message": "Daily export limit reached (100). It resets at 00:00 UTC. Upgrade your plan for a higher limit.",
    "hint": "The limit resets at 00:00 UTC. A higher plan raises it: https://www.gpt-video.com/app/billing.",
    "requestId": "req_8b1e5a3d7f0c2e6b9a4d1f72"
  }
}

A composition that does not exist

POST /v1/compositions/cmp_7a1f5d3c9e0b42d8f6a2/exports

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_9e1a4c7f2b0d5e8a3c6f1b47"
  }
}

Errors

CodeStatusWhenWhat to do
INSUFFICIENT_CREDITS402See the error reference.Stop and tell the user.
PLAN_REQUIRED402An export longer than the API bonus pays forStop and tell the user.
NOT_FOUND404A composition that does not existChange the request, then send it again.
CONFLICT409A composition that uses a file the API cannot useRead the resource again, then decide. Do not send the same request again.
NOT_READY409The framing of the clip is still being computedWait for Retry-After, then send the same request again.
DAILY_LIMIT_REACHED429The exports of the day are used upStop until the limit resets at 00:00 UTC.

Every call can also answer these errors. VALIDATION_FAILED, UNKNOWN_PARAMETER, IDEMPOTENCY_KEY_REQUIRED, UNAUTHORIZED, SCOPE_MISSING, IDEMPOTENCY_IN_PROGRESS, PAYLOAD_TOO_LARGE, IDEMPOTENCY_KEY_REUSED, RATE_LIMITED, INTERNAL, UNAVAILABLE.

Cost

Uses one export of the daily allowance, which resets at 00:00 UTC, and no credits. When the API bonus pays for it, it also uses one bonus credit. Nothing is returned if the export fails or is cancelled.

  • Paid by the API bonus, it uses 1 bonus credit.
  • When the API bonus pays, an account can make 5 exports a day, each up to 600 seconds long.
  • See API pricing for who pays first.
  • get_export (GET /v1/exports/{exportId}) Get an export
  • list_exports (GET /v1/projects/{projectId}/exports) List the exports of a project
  • accept_clip (POST /v1/clips/{clipId}/accept) Accept a clip
  • get_composition (GET /v1/compositions/{compositionId}) Get a composition
  • get_job (GET /v1/jobs/{jobId}) Get a job
  • get_composition_captions (GET /v1/compositions/{compositionId}/captions) Get the captions of a composition

Questions

What happens if my request times out and I send it again?

Send it again with the same Idempotency-Key. You get the same export back and no second export is used from the daily allowance; if the first try stopped before the render started, the retry starts it. A new key is a new export.

Why does the answer have no download link?

The answer to this call is kept and repeated for retries, and a download link must not outlive its few minutes. Read the export with get_export (GET /v1/exports/{exportId}): once it is done, every read gives a fresh downloadUrl.

What does NOT_READY mean here?

The clip is still being framed on the speaker's face. Wait the seconds in Retry-After and send the same request again; nothing was used.

Why is a composition refused with CONFLICT?

It uses a file the API cannot use, which the GPT-Video app put in it, such as a video made for a UGC project. Remove that file in the app, then export again; nothing was used.

How long can an export paid by the API bonus be?

Up to 10 minutes. A longer composition answers PLAN_REQUIRED for an account that is not on the Creator or Studio plan; on those plans, the exports of the plan have no such limit.

View as Markdown