Get an export
get_exportGET/v1/exports/{exportId}Beta
Returns an export: its status, its file and, once it is done, a fresh download link.
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 to follow an export that create_export (POST /v1/compositions/{compositionId}/exports) started, and to download its file. While the export is queued or rendering, add ?wait= with up to 25 seconds to hold the request until it ends, then call again if it is still working. Once the status is done, downloadUrl downloads the MP4 with no API key: the link is short-lived and every read gives a new one, so read the export again right before downloading. Export files are kept for a limited time; see fileDeletesAt. A failed or cancelled export says what happened in errorMessage: export the composition again with create_export and a new Idempotency-Key.
Example use
A publishing script holds the request with ?wait= until an export is done, then reads the export once more right before it downloads the MP4, because the link in downloadUrl is short-lived.
Endpoint
GET https://api.gpt-video.com/v1/exports/{exportId}- Scope
clips:read. - Rate limit 120 requests a minute for each key and 240 for each account, shared by every
readcall. See rate limits. - No
Idempotency-Key.
Parameters
Path
| Name | Type | Required | Description |
|---|---|---|---|
exportId | string | Required | The id of the export, as create_export (POST /v1/compositions/{compositionId}/exports) or list_exports (GET /v1/projects/{projectId}/exports) returned it. It starts with rnd_. Matches ^rnd_[0-9a-f]{20}$. |
Query
| Name | Type | Required | Description |
|---|---|---|---|
wait | integer | Optional | Seconds to hold the request while the work is still running, up to 25. Leave it out to answer at once. If many requests of the account are already waiting, it answers at once; wait a few seconds before you read again. From 0 to 25. |
Request
Get a finished export.
curl "https://api.gpt-video.com/v1/exports/rnd_0f6b3e9d2c7a4158b4a3" \
-H "Authorization: Bearer $GPT_VIDEO_API_KEY"const res = await fetch("https://api.gpt-video.com/v1/exports/rnd_0f6b3e9d2c7a4158b4a3", {
method: "GET",
headers: {
"Authorization": `Bearer ${process.env.GPT_VIDEO_API_KEY}`,
},
});
const data = await res.json();
console.log(data);import os
import requests
r = requests.get(
"https://api.gpt-video.com/v1/exports/rnd_0f6b3e9d2c7a4158b4a3",
headers={
"Authorization": f"Bearer {os.environ['GPT_VIDEO_API_KEY']}",
},
)
data = r.json()
print(data){
"method": "tools/call",
"params": {
"name": "get_export",
"arguments": {
"exportId": "rnd_0f6b3e9d2c7a4158b4a3"
}
}
}Response
A successful call answers HTTP 200. Returns a Export object in export.
Fields to check
| Name | Type | Description |
|---|---|---|
export.id | string | The export id. It starts with rnd_. |
export.jobId | string or null | The 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.status | string | queued and rendering are still working; done, failed and cancelled are final. |
export.downloadUrl | string or null | A 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.downloadUrlExpiresAt | string or null | When downloadUrl stops working; null when there is no link. |
Response example
{
"export": {
"id": "rnd_0f6b3e9d2c7a4158b4a3",
"compositionId": "cmp_4e8c2a6f09d14b73a1e5",
"projectId": "prj_7c2e9a4f1b3d4e8096a5",
"jobId": "job_a3e9d05c7b1f4e2896d4",
"revision": 0,
"status": "done",
"progress": 1,
"errorMessage": null,
"createdAt": "2026-09-01T10:10:00.000Z",
"finishedAt": "2026-09-01T10:15:00.000Z",
"file": {
"mimeType": "video/mp4",
"sizeBytes": 18874368,
"durationSec": 30,
"width": 1080,
"height": 1920
},
"downloadUrl": "https://www.gpt-video.com/media/ast_c47d2e8a19b54f06d2e1?exp=1788258600&sig=9b2e61c04d7f3a58e1b6c2d9f0a4e7b3",
"downloadUrlExpiresAt": "2026-09-01T10:30:00.000Z",
"fileDeletesAt": "2026-09-15T10:15:00.000Z",
"fileDeletedAt": null
}
}All response fields
| Name | Type | Required | Description |
|---|---|---|---|
export | Export object | Required | Described in Export object. |
More examples
Wait for an export to finish
GET /v1/exports/rnd_0f6b3e9d2c7a4158b4a3?wait=25
{
"export": {
"id": "rnd_0f6b3e9d2c7a4158b4a3",
"compositionId": "cmp_4e8c2a6f09d14b73a1e5",
"projectId": "prj_7c2e9a4f1b3d4e8096a5",
"jobId": "job_a3e9d05c7b1f4e2896d4",
"revision": 0,
"status": "done",
"progress": 1,
"errorMessage": null,
"createdAt": "2026-09-01T10:10:00.000Z",
"finishedAt": "2026-09-01T10:15:00.000Z",
"file": {
"mimeType": "video/mp4",
"sizeBytes": 18874368,
"durationSec": 30,
"width": 1080,
"height": 1920
},
"downloadUrl": "https://www.gpt-video.com/media/ast_c47d2e8a19b54f06d2e1?exp=1788258600&sig=9b2e61c04d7f3a58e1b6c2d9f0a4e7b3",
"downloadUrlExpiresAt": "2026-09-01T10:30:00.000Z",
"fileDeletesAt": "2026-09-15T10:15:00.000Z",
"fileDeletedAt": null
}
}An export that does not exist
GET /v1/exports/rnd_2e9c7a1b5d3f4086c4e8
{
"error": {
"code": "NOT_FOUND",
"message": "Export rnd_2e9c7a1b5d3f4086c4e8 not found",
"hint": "Check the id. An id that belongs to another account is not found either.",
"requestId": "req_2b7d0e5a8c1f4a6e9b3d7c50"
}
}Errors
| Code | Status | When | What to do |
|---|---|---|---|
NOT_FOUND | 404 | An export that does not exist | Change the request, then send it again. |
Every call can also answer these errors. VALIDATION_FAILED, UNKNOWN_PARAMETER, UNAUTHORIZED, SCOPE_MISSING, RATE_LIMITED, INTERNAL, UNAVAILABLE.
Cost
No credits are used.
Related operations
create_export(POST /v1/compositions/{compositionId}/exports) Export a compositionlist_exports(GET /v1/projects/{projectId}/exports) List the exports of a projectget_job(GET /v1/jobs/{jobId}) Get a jobget_composition_captions(GET /v1/compositions/{compositionId}/captions) Get the captions of a compositiondelete_composition(DELETE /v1/compositions/{compositionId}) Delete a composition
Questions
How long does the download link work?
For 15 minutes; downloadUrlExpiresAt says until when. It downloads this file only. Read the export again for a new link at any time while the file is kept.
Why is downloadUrl null on a finished export?
The file was deleted to free space: fileDeletedAt says when. Export the composition again with create_export (POST /v1/compositions/{compositionId}/exports) to get a new file.
How do I wait for an export without polling in a tight loop?
Send ?wait=25. The request is held until the export ends or 25 seconds pass, whichever comes first, and then answers the export as it is. If many requests of the account are already waiting, it answers at once instead; wait a few seconds before you read again.