---
title: "List the tool runs | GPT-Video API reference"
description: "Lists the voiceovers, audio separations and brainstorms of the account, newest first."
url: "https://www.gpt-video.com/developers/api/list-tool-runs"
operation: "list_tool_runs"
method: "GET"
path: "/v1/tool-runs"
scope: "clips:read"
---

Do not assume endpoints have parameters other than the ones explicitly specified.

# List the tool runs

Operation id `list_tool_runs`. Request `GET /v1/tool-runs`.

Lists the voiceovers, audio separations and brainstorms of the account, newest first.

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 find the tool runs of the account, for example to recover the run of a request whose answer you lost. Pass tool to see one kind only. The list is newest first and paged with cursor and limit. A page never carries download links: read a run with get_tool_run (`GET /v1/tool-runs/{toolRunId}`) to get one.

## Example use

A script that lost the answer of a voiceover request lists the latest runs of that tool to find it again. It then reads the run with get_tool_run (`GET /v1/tool-runs/{toolRunId}`) to get a fresh download link.

## Endpoint

```text
GET https://api.gpt-video.com/v1/tool-runs
```

- Scope `clips:read`.
- Rate limit 120 requests a minute for each key and 240 for each account, shared by every `read` call. See [rate limits](/developers/rate-limits.md).
- No `Idempotency-Key`.

## Parameters

### Query

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `tool` | string | Optional | Only the runs of this tool. Leave it out to list every tool. One of `voiceover`, `audio_separation`, `brainstorm`. |
| `limit` | integer | Optional | How many items to return, from 1 to 100. Defaults to 20. From 1 to 100. Default `20`. |
| `cursor` | string | Optional | The nextCursor value from the previous page. Leave it out to get the first page. From 1 to 512 characters. |

## Request

List the tool runs.

```bash title="curl"
curl "https://api.gpt-video.com/v1/tool-runs" \
  -H "Authorization: Bearer $GPT_VIDEO_API_KEY"
```

```ts title="TypeScript"
const res = await fetch("https://api.gpt-video.com/v1/tool-runs", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${process.env.GPT_VIDEO_API_KEY}`,
  },
});
const data = await res.json();
console.log(data);
```

```python title="Python"
import os

import requests

r = requests.get(
    "https://api.gpt-video.com/v1/tool-runs",
    headers={
        "Authorization": f"Bearer {os.environ['GPT_VIDEO_API_KEY']}",
    },
)
data = r.json()
print(data)
```

```json title="MCP (Full)"
{
  "method": "tools/call",
  "params": {
    "name": "list_tool_runs",
    "arguments": {}
  }
}
```

## Response

A successful call answers HTTP 200.

### Fields to check

| Name | Type | Description |
| --- | --- | --- |
| `data[].id` | string | The tool run id. It starts with run_. |
| `data[].status` | string | queued and running are still working; done and failed are final. |
| `data[].file.downloadUrl` | string or null | A link to download the file, on a read of a finished run; null otherwise. |
| `data[].file.downloadUrlExpiresAt` | string or null | An ISO 8601 time in UTC. |
| `data[].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. |
| `hasMore` | boolean | true when there are more items after this page. |
| `nextCursor` | string or null | Send it as cursor to get the next page. It is null on the last page. |

### Response example

```json title="HTTP 200"
{
  "data": [
    {
      "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": null,
        "downloadUrlExpiresAt": null
      },
      "ideas": null,
      "jobId": "job_bd92cb70ed9c45575464",
      "createdAt": "2026-08-31T21:30:00.000Z",
      "finishedAt": "2026-08-31T21:32:00.000Z"
    }
  ],
  "hasMore": false,
  "nextCursor": null
}
```

**All response fields**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `data` | array of objects | Required | The items of this page. |
| `data[]` | Tool run object | Optional | Described in [Tool run object](/developers/objects.md#tool-run). |
| `hasMore` | boolean | Required | true when there are more items after this page. |
| `nextCursor` | string or null | Required | Send it as cursor to get the next page. It is null on the last page. |

**More examples**

#### List the voiceovers only

`GET /v1/tool-runs?tool=voiceover&limit=10`

```json title="HTTP 200"
{
  "data": [
    {
      "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": null,
        "downloadUrlExpiresAt": null
      },
      "ideas": null,
      "jobId": "job_bd92cb70ed9c45575464",
      "createdAt": "2026-08-31T21:30:00.000Z",
      "finishedAt": "2026-08-31T21:32:00.000Z"
    }
  ],
  "hasMore": false,
  "nextCursor": null
}
```

## Errors

Every call can also answer these errors. [`VALIDATION_FAILED`](/developers/errors.md#VALIDATION_FAILED), [`UNKNOWN_PARAMETER`](/developers/errors.md#UNKNOWN_PARAMETER), [`UNAUTHORIZED`](/developers/errors.md#UNAUTHORIZED), [`SCOPE_MISSING`](/developers/errors.md#SCOPE_MISSING), [`RATE_LIMITED`](/developers/errors.md#RATE_LIMITED), [`INTERNAL`](/developers/errors.md#INTERNAL), [`UNAVAILABLE`](/developers/errors.md#UNAVAILABLE).

## Cost

No credits are used.

## Related operations

- [`get_tool_run`](/developers/api/get-tool-run.md) (`GET /v1/tool-runs/{toolRunId}`) Get a tool run
- [`create_voiceover`](/developers/api/create-voiceover.md) (`POST /v1/voiceovers`) Create a voiceover
- [`separate_audio`](/developers/api/separate-audio.md) (`POST /v1/audio-separations`) Separate the voices of a video
- [`brainstorm_ideas`](/developers/api/brainstorm-ideas.md) (`POST /v1/brainstorms`) Brainstorm video ideas

## Questions

### Why is downloadUrl null in the list?

A page never carries download links. Read the run with get_tool_run (`GET /v1/tool-runs/{toolRunId}`): once it is done, every read gives a fresh downloadUrl.

### Does the list include failed runs?

Yes, every run is listed with its status. A failed run has no file and no ideas; start it again with a new Idempotency-Key.
