Get a tool run
get_tool_runGET/v1/tool-runs/{toolRunId}Beta
Returns a tool run: its status and, once it is done, its audio file with a fresh download link, or its ideas.
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 a voiceover, an audio separation or a brainstorm. While the run is queued or running, 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, a voiceover or a separation has its file, whose downloadUrl downloads the MP3 with no API key: the link is short-lived and every read gives a new one. A brainstorm has its ideas. A failed run says what happened in errorMessage: start it again with a new Idempotency-Key.
Example use
A script that started a voiceover reads the run with ?wait= until it is done. Then it downloads the MP3 from the download link, which changes on every read.
Endpoint
GET https://api.gpt-video.com/v1/tool-runs/{toolRunId}- 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 |
|---|---|---|---|
toolRunId | string | Required | The id of the tool run, as create_voiceover (POST /v1/voiceovers), separate_audio (POST /v1/audio-separations), brainstorm_ideas (POST /v1/brainstorms) or list_tool_runs (GET /v1/tool-runs) returned it. It starts with run_. Matches ^run_[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 voiceover.
curl "https://api.gpt-video.com/v1/tool-runs/run_b014441ea91a51965c46" \
-H "Authorization: Bearer $GPT_VIDEO_API_KEY"const res = await fetch("https://api.gpt-video.com/v1/tool-runs/run_b014441ea91a51965c46", {
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/tool-runs/run_b014441ea91a51965c46",
headers={
"Authorization": f"Bearer {os.environ['GPT_VIDEO_API_KEY']}",
},
)
data = r.json()
print(data){
"method": "tools/call",
"params": {
"name": "get_tool_run",
"arguments": {
"toolRunId": "run_b014441ea91a51965c46"
}
}
}Response
A successful call answers HTTP 200. Returns a Tool run object in toolRun.
Fields to check
| Name | Type | Description |
|---|---|---|
toolRun.id | string | The tool run id. It starts with run_. |
toolRun.status | string | queued and running are still working; done and failed are final. |
toolRun.file.downloadUrl | string or null | A link to download the file, on a read of a finished run; null otherwise. |
toolRun.file.downloadUrlExpiresAt | string or null | An ISO 8601 time in UTC. |
toolRun.jobId | string or null | The job that carries out the run, to follow with get_job (GET /v1/jobs/{jobId}); null once it is gone. |
Response example
{
"toolRun": {
"id": "run_b014441ea91a51965c46",
"tool": "voiceover",
"status": "done",
"progress": 1,
"errorMessage": null,
"voiceover": {
"title": "Launch voiceover",
"script": "Meet the editor that turns one long video into ten short clips.",
"voice": "en-aria",
"language": "en"
},
"separation": null,
"brainstorm": null,
"file": {
"assetId": "ast_e8a35ed674148f27b585",
"mimeType": "audio/mpeg",
"durationSec": 14,
"sizeBytes": 224000,
"downloadUrl": "https://www.gpt-video.com/media/ast_e8a35ed674148f27b585?exp=1788258600&sig=4c1e9a7f2b5d8e03a6c9f1b4d7e2a5c8",
"downloadUrlExpiresAt": "2026-09-01T10:30:00.000Z"
},
"ideas": null,
"jobId": "job_bd92cb70ed9c45575464",
"createdAt": "2026-08-31T21:30:00.000Z",
"finishedAt": "2026-08-31T21:32:00.000Z"
}
}All response fields
| Name | Type | Required | Description |
|---|---|---|---|
toolRun | Tool run object | Required | Described in Tool run object. |
More examples
Wait for a run to finish
GET /v1/tool-runs/run_b014441ea91a51965c46?wait=25
{
"toolRun": {
"id": "run_b014441ea91a51965c46",
"tool": "voiceover",
"status": "done",
"progress": 1,
"errorMessage": null,
"voiceover": {
"title": "Launch voiceover",
"script": "Meet the editor that turns one long video into ten short clips.",
"voice": "en-aria",
"language": "en"
},
"separation": null,
"brainstorm": null,
"file": {
"assetId": "ast_e8a35ed674148f27b585",
"mimeType": "audio/mpeg",
"durationSec": 14,
"sizeBytes": 224000,
"downloadUrl": "https://www.gpt-video.com/media/ast_e8a35ed674148f27b585?exp=1788258600&sig=4c1e9a7f2b5d8e03a6c9f1b4d7e2a5c8",
"downloadUrlExpiresAt": "2026-09-01T10:30:00.000Z"
},
"ideas": null,
"jobId": "job_bd92cb70ed9c45575464",
"createdAt": "2026-08-31T21:30:00.000Z",
"finishedAt": "2026-08-31T21:32:00.000Z"
}
}A tool run that does not exist
GET /v1/tool-runs/run_774e9c335fb2d153918a
{
"error": {
"code": "NOT_FOUND",
"message": "Tool run run_774e9c335fb2d153918a not found",
"hint": "Check the id. An id that belongs to another account is not found either.",
"requestId": "req_0e4a8c2f6b1d5e9a3c7f0b28"
}
}Errors
| Code | Status | When | What to do |
|---|---|---|---|
NOT_FOUND | 404 | A tool run 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_voiceover(POST /v1/voiceovers) Create a voiceoverseparate_audio(POST /v1/audio-separations) Separate the voices of a videobrainstorm_ideas(POST /v1/brainstorms) Brainstorm video ideaslist_tool_runs(GET /v1/tool-runs) List the tool runsget_job(GET /v1/jobs/{jobId}) Get a jobget_asset(GET /v1/assets/{assetId}) Get an asset
Questions
How long does the download link work?
For 15 minutes; downloadUrlExpiresAt says until when. It downloads this file only. Read the run again for a new link.
How do I wait for a run without polling in a tight loop?
Send ?wait=25. The request is held until the run ends or 25 seconds pass, whichever comes first, and then answers the run 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.