---
title: "Update a project | GPT-Video API reference"
description: "Renames an Auto Clip project or changes its settings, leaving every field you do not send as it was."
url: "https://www.gpt-video.com/developers/api/update-project"
operation: "update_project"
method: "PATCH"
path: "/v1/projects/{projectId}"
scope: "clips:write"
---

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

# Update a project

Operation id `update_project`. Request `PATCH /v1/projects/{projectId}`.

Renames an Auto Clip project or changes its settings, leaving every field you do not send as it was.

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

Use it to choose the settings listed in missingSettings, or to change them before the next analysis. Only the fields you send change. The source video cannot be changed: sending sourceAssetId is refused, and to analyze another video you create another project. Settings changed while an analysis is waiting to start are used by that analysis; the price depends only on the source video.

## Example use

A tool shows the missing settings of a project to a person, sends their choices with update_project (`PATCH /v1/projects/{projectId}`), and reads the project again to see that missingSettings is empty before it calls analyze_project (`POST /v1/projects/{projectId}/analyze`).

## Endpoint

```text
PATCH https://api.gpt-video.com/v1/projects/{projectId}
```

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

## Parameters

### Path

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `projectId` | string | Required | The project id. It starts with prj_. Matches `^prj_[0-9a-f]{20}$`. |

### Body

The body is optional. Send only the fields you want to change.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `title` | string | Optional | The new name of the project. From 1 to 120 characters. Matches `\S`. |
| `settings` | object | Optional | Auto Clip settings. A field you leave out is left as it is, and every one can be set later with update_project (`PATCH /v1/projects/{projectId}`). |
| `settings.language` | string | Optional | The language spoken in the video: en, it, or auto to detect it. One of `auto`, `it`, `en`. |
| `settings.clipCount` | integer | Optional | How many clips the analysis proposes. From 1 to 100. From 1 to 100. |
| `settings.minDurationSec` | number | Optional | The shortest clip the analysis may propose, in seconds. From 5 to 180, and not longer than maxDurationSec when the analysis starts. From 5 to 180. |
| `settings.maxDurationSec` | number | Optional | The longest clip the analysis may propose, in seconds. From 10 to 300. From 10 to 300. |
| `settings.objective` | string | Optional | What the clips should be good at. get_setting_options (`GET /v1/reference/setting-options`) lists every objective with what it means. One of `viral`, `educational`, `entertaining`, `emotional`, `controversial`, `howto`, `business`. |
| `settings.captionStyle` | string | Optional | The caption style of the clips. get_setting_options (`GET /v1/reference/setting-options`) lists every style with what it looks like. One of `bold-karaoke`, `word-pop`, `boxed`, `outline`. |
| `settings.reframe` | string | Optional | How a clip follows the speaker: face follows the face of the speaker, center keeps the middle of the frame. One of `face`, `center`. |
| `settings.instructions` | string or null | Optional | Free text that tells the analysis what to look for, such as only the moments where a given person speaks. At most 2000 characters; null removes them. At most 2000 characters. |
| `settings.vocabulary` | string or null | Optional | Names, brands and jargon the transcription should spell right, separated by commas. It is used when the video is transcribed, so set it before the first analysis. At most 311 characters; null removes it. At most 311 characters. |

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

## Request

Choose the settings a draft is missing.

```bash title="curl"
curl -X PATCH "https://api.gpt-video.com/v1/projects/prj_1d8b6e0c47a24f93b1c2" \
  -H "Authorization: Bearer $GPT_VIDEO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "settings": {
      "language": "en",
      "minDurationSec": 20,
      "maxDurationSec": 45,
      "captionStyle": "bold-karaoke",
      "reframe": "face"
    }
  }'
```

```ts title="TypeScript"
const res = await fetch("https://api.gpt-video.com/v1/projects/prj_1d8b6e0c47a24f93b1c2", {
  method: "PATCH",
  headers: {
    "Authorization": `Bearer ${process.env.GPT_VIDEO_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "settings": {
      "language": "en",
      "minDurationSec": 20,
      "maxDurationSec": 45,
      "captionStyle": "bold-karaoke",
      "reframe": "face"
    }
  }),
});
const data = await res.json();
console.log(data);
```

```python title="Python"
import os

import requests

r = requests.patch(
    "https://api.gpt-video.com/v1/projects/prj_1d8b6e0c47a24f93b1c2",
    headers={
        "Authorization": f"Bearer {os.environ['GPT_VIDEO_API_KEY']}",
    },
    json={
        "settings": {
            "language": "en",
            "minDurationSec": 20,
            "maxDurationSec": 45,
            "captionStyle": "bold-karaoke",
            "reframe": "face"
        }
    },
)
data = r.json()
print(data)
```

```json title="MCP (Full)"
{
  "method": "tools/call",
  "params": {
    "name": "update_project",
    "arguments": {
      "projectId": "prj_1d8b6e0c47a24f93b1c2",
      "settings": {
        "language": "en",
        "minDurationSec": 20,
        "maxDurationSec": 45,
        "captionStyle": "bold-karaoke",
        "reframe": "face"
      }
    }
  }
}
```

## Response

A successful call answers HTTP 200. Returns a [Project object](/developers/objects.md#project) in `project`.

### Fields to check

| Name | Type | Description |
| --- | --- | --- |
| `project.id` | string | The project id. It starts with prj_. |
| `project.status` | string | draft has not been analyzed yet, processing is being analyzed, ready has clips, failed means the last analysis failed and errorMessage says why. |

### Response example

```json title="HTTP 200"
{
  "project": {
    "id": "prj_1d8b6e0c47a24f93b1c2",
    "kind": "autoclip",
    "title": "Weekly podcast",
    "status": "draft",
    "sourceAssetId": null,
    "compositionId": null,
    "settings": {
      "language": "en",
      "clipCount": 5,
      "minDurationSec": 20,
      "maxDurationSec": 45,
      "objective": "educational",
      "captionStyle": "bold-karaoke",
      "reframe": "face",
      "instructions": null,
      "vocabulary": null
    },
    "missingSettings": [],
    "splitScreen": null,
    "streamer": null,
    "redditStory": null,
    "fakeText": null,
    "vibeEdit": null,
    "errorMessage": null,
    "createdAt": "2026-09-01T09:50:00.000Z",
    "updatedAt": "2026-09-01T11:05:00.000Z"
  }
}
```

**All response fields**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `project` | Project object | Required | Described in [Project object](/developers/objects.md#project). |

**More examples**

#### Rename a project and remove its instructions

`PATCH /v1/projects/prj_7c2e9a4f1b3d4e8096a5`

```json title="Request body"
{
  "title": "Founder interview, part one",
  "settings": {
    "instructions": null
  }
}
```

```json title="HTTP 200"
{
  "project": {
    "id": "prj_7c2e9a4f1b3d4e8096a5",
    "kind": "autoclip",
    "title": "Founder interview, part one",
    "status": "ready",
    "sourceAssetId": "ast_3f9a1c7e5b2d4086a1c4",
    "compositionId": null,
    "settings": {
      "language": "en",
      "clipCount": 3,
      "minDurationSec": 15,
      "maxDurationSec": 60,
      "objective": "viral",
      "captionStyle": "word-pop",
      "reframe": "face",
      "instructions": null,
      "vocabulary": null
    },
    "missingSettings": [],
    "splitScreen": null,
    "streamer": null,
    "redditStory": null,
    "fakeText": null,
    "vibeEdit": null,
    "errorMessage": null,
    "createdAt": "2026-09-01T09:10:00.000Z",
    "updatedAt": "2026-09-01T11:05:00.000Z"
  }
}
```

#### A project that does not exist

`PATCH /v1/projects/prj_9f0d3b7e1c5a4d28b6f3`

```json title="Request body"
{
  "title": "Renamed"
}
```

```json title="HTTP 404"
{
  "error": {
    "code": "NOT_FOUND",
    "message": "Project prj_9f0d3b7e1c5a4d28b6f3 not found",
    "hint": "Check the id. An id that belongs to another account is not found either.",
    "requestId": "req_fc830e598aa2f3dfc22a8c1a"
  }
}
```

## Errors

| Code | Status | When | What to do |
| --- | --- | --- | --- |
| [`NOT_FOUND`](/developers/errors.md#NOT_FOUND) | 404 | A project that does not exist | Change the request, then send it again. |
| [`CONFLICT`](/developers/errors.md#CONFLICT) | 409 | The project is not an Auto Clip project. Other kinds have their own calls, such as update_split_screen_project (`PATCH /v1/projects/{projectId}/split-screen`), or apply_timeline_operations (`POST /v1/projects/{projectId}/timeline/operations`) for a Vibe Editing edit. | Read the resource again, then decide. Do not send the same request again. |

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), [`PAYLOAD_TOO_LARGE`](/developers/errors.md#PAYLOAD_TOO_LARGE), [`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_project`](/developers/api/get-project.md) (`GET /v1/projects/{projectId}`) Get a project
- [`estimate_analysis`](/developers/api/estimate-analysis.md) (`POST /v1/projects/{projectId}/analyze/estimate`) Estimate the credits of an analysis or a build
- [`analyze_project`](/developers/api/analyze-project.md) (`POST /v1/projects/{projectId}/analyze`) Analyze a project
- [`get_setting_options`](/developers/api/get-setting-options.md) (`GET /v1/reference/setting-options`) Get the setting options
- [`create_project`](/developers/api/create-project.md) (`POST /v1/projects`) Create a project

## Questions

### How do I clear a setting?

Send null for instructions or vocabulary to remove them. The other settings cannot be cleared, only changed to another value.

### Can I set minDurationSec higher than maxDurationSec?

Yes, for a moment: each change is saved as it comes, so you can raise the minimum before the maximum. analyze_project (`POST /v1/projects/{projectId}/analyze`) refuses while the minimum is longer than the maximum.

### Why is my split screen project refused?

update_project (`PATCH /v1/projects/{projectId}`) changes Auto Clip projects only. Every other kind has its own operations, such as update_split_screen_project (`PATCH /v1/projects/{projectId}/split-screen`) for a split screen project or update_streamer_project (`PATCH /v1/projects/{projectId}/streamer`) for a streamer project.
