---
title: "Brainstorm video ideas | GPT-Video API reference"
description: "Starts writing ideas for short videos on a topic, and returns the tool run that holds them once it is done."
url: "https://www.gpt-video.com/developers/api/brainstorm-ideas"
operation: "brainstorm_ideas"
method: "POST"
path: "/v1/brainstorms"
scope: "spend"
---

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

# Brainstorm video ideas

Operation id `brainstorm_ideas`. Request `POST /v1/brainstorms`.

Starts writing ideas for short videos on a topic, and returns the tool run that holds them once it is done.

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 get ideas for short videos on a topic: each idea has a title, a hook, an outline, a format and why it works. Say the kind of video with videoType (get_setting_options (`GET /v1/reference/setting-options`) lists them), the language of the ideas and how many you want. The call answers 202 at once with the run, queued, and a Location to follow; read it with get_tool_run (`GET /v1/tool-runs/{toolRunId}`) (with ?wait= to hold the request) until it is done, then read the ideas in its ideas field. Always send an Idempotency-Key, the same one on every retry: a retry of the same request returns the same run and never uses a second tool run.

## Example use

Each Monday a content team asks for ten ideas about its next product launch, with videoType any. It reads the hooks and outlines from get_tool_run (`GET /v1/tool-runs/{toolRunId}`) and picks the ones to film.

## Endpoint

```text
POST https://api.gpt-video.com/v1/brainstorms
```

- Scope `spend`.
- Rate limit 10 requests a minute for each key and 20 for each account, shared by every `spend` call. See [rate limits](/developers/rate-limits.md).
- `Idempotency-Key` is required.
- It starts work that runs on its own. The answer comes back before the work is done.

## Parameters

### Headers

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Idempotency-Key` | string | Required | This 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](/developers/pagination-and-idempotency.md). |

### Body

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `topic` | string | Required | What the videos are about, up to 300 characters. From 1 to 300 characters. |
| `tone` | string | Optional | The tone of the videos, like funny or serious, up to 60 characters. At most 60 characters. |
| `audience` | string | Optional | Who the videos are for, up to 200 characters. At most 200 characters. |
| `videoType` | string | Required | The kind of video the ideas are for: story, fake_text, split_screen, or any. One of `story`, `fake_text`, `split_screen`, `any`. |
| `language` | string | Required | The language of the ideas: en for English, it for Italian. One of `en`, `it`. |
| `count` | integer | Required | How many ideas to write, from 3 to 30. From 3 to 30. |

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

## Request

Ideas for story videos.

```bash title="curl"
# 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/brainstorms" \
  -H "Authorization: Bearer $GPT_VIDEO_API_KEY" \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "topic": "Morning routines for busy parents",
    "videoType": "story",
    "language": "en",
    "count": 5
  }'
```

```ts title="TypeScript"
// 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/brainstorms", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.GPT_VIDEO_API_KEY}`,
    "Idempotency-Key": idempotencyKey,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "topic": "Morning routines for busy parents",
    "videoType": "story",
    "language": "en",
    "count": 5
  }),
});
const data = await res.json();
console.log(data);
```

```python title="Python"
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/brainstorms",
    headers={
        "Authorization": f"Bearer {os.environ['GPT_VIDEO_API_KEY']}",
        "Idempotency-Key": idempotency_key,
    },
    json={
        "topic": "Morning routines for busy parents",
        "videoType": "story",
        "language": "en",
        "count": 5
    },
)
data = r.json()
print(data)
```

```json title="MCP (Full)"
{
  "method": "tools/call",
  "params": {
    "name": "brainstorm_ideas",
    "arguments": {
      "topic": "Morning routines for busy parents",
      "videoType": "story",
      "language": "en",
      "count": 5,
      "confirm": true,
      "idempotencyKey": "REPLACE-WITH-A-NEW-UUID-FOR-THIS-CALL"
    }
  }
}
```

## Response

A successful call answers HTTP 202. Returns a [Tool run object](/developers/objects.md#tool-run) 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. |
| `paidWith` | string or null | Who 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/tool-runs/run_5e8a1c3f7d2b4096a1e4`

```json title="HTTP 202"
{
  "toolRun": {
    "id": "run_5e8a1c3f7d2b4096a1e4",
    "tool": "brainstorm",
    "status": "queued",
    "progress": 0,
    "errorMessage": null,
    "file": null,
    "ideas": null,
    "jobId": "job_2c7f9e1a4d6b48035f9e",
    "createdAt": "2026-09-01T11:00:00.000Z",
    "finishedAt": null,
    "voiceover": null,
    "separation": null,
    "brainstorm": {
      "topic": "Morning routines for busy parents",
      "tone": "",
      "audience": "",
      "videoType": "story",
      "language": "en",
      "count": 5
    }
  },
  "paidWith": "plan"
}
```

**All response fields**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `toolRun` | Tool run object | Required | Described in [Tool run object](/developers/objects.md#tool-run). |
| `paidWith` | string or null | Required | Who 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 tool runs of the day are used up

`POST /v1/brainstorms`

```json title="Request body"
{
  "topic": "Morning routines for busy parents",
  "videoType": "any",
  "language": "en",
  "count": 10
}
```

```json title="HTTP 429"
{
  "error": {
    "code": "DAILY_LIMIT_REACHED",
    "message": "Daily limit of tool runs 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_6a2d9f1c4e8b3a7d0f5c2e94"
  }
}
```

## Errors

| Code | Status | When | What to do |
| --- | --- | --- | --- |
| [`INSUFFICIENT_CREDITS`](/developers/errors.md#INSUFFICIENT_CREDITS) | 402 | See the error reference. | Stop and tell the user. |
| [`PLAN_REQUIRED`](/developers/errors.md#PLAN_REQUIRED) | 402 | See the error reference. | Stop and tell the user. |
| [`DAILY_LIMIT_REACHED`](/developers/errors.md#DAILY_LIMIT_REACHED) | 429 | The tool runs of the day are used up | Stop until the limit resets at 00:00 UTC. |

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

## Cost

Uses one tool run of the plan's daily allowance, which resets at 00:00 UTC. When the API bonus pays, it also uses one bonus credit. Nothing is returned if the run fails.

- Paid by the API bonus, it uses 1 bonus credit.
- When the API bonus pays, an account can run 10 tools a day.
- See [API pricing](/developers/pricing.md) for who pays first.

## Related operations

- [`get_tool_run`](/developers/api/get-tool-run.md) (`GET /v1/tool-runs/{toolRunId}`) Get a tool run
- [`list_tool_runs`](/developers/api/list-tool-runs.md) (`GET /v1/tool-runs`) List the tool runs
- [`get_setting_options`](/developers/api/get-setting-options.md) (`GET /v1/reference/setting-options`) Get the setting options

## 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 run back and no second tool run is used from the daily allowance. A new key starts a new run.

### Where are the ideas?

In the ideas field of the run, once get_tool_run (`GET /v1/tool-runs/{toolRunId}`) says it is done. Until then ideas is null.
