# Update video

URL: https://clippie.ai/developers/docs/update-video

Restyles a video project before you render it: caption style, position, size, colours, case, outline and shadow; background clip (backgroundVideoId or backgroundGenre) and its start; music and volume; frame shape; mirroring; and template fields (reddit: card, roblox: emojis, ...). These changes are instant and free, and the answer has fresh stills (stills: false skips them). A change that needs new audio (a new voice, a script edit, silence removal) is charged like the app and returns { job }: run it with dryRun: true first.

## At a glance

| Property | Value |
| --- | --- |
| REST | `PATCH https://api.clippie.ai/v1/videos/:projectId` |
| MCP tool | `update_video` |
| Scope | `create` |
| Cost | Spends credits or minutes, at the same prices as the app. Send `"dryRun": true` (or call [estimate_cost](https://clippie.ai/developers/docs/estimate-cost.md)) first to see the exact cost without spending anything. |

## Parameters

| Name | In | Type | Required | Default | Description |
| --- | --- | --- | --- | --- | --- |
| `projectId` | path | string | Yes |  | The project id: output.projectId of a job, an id from list_videos, or the id in an editor URL. 1-64 chars. |
| `template` | body | string | No |  | Only look among this template's projects (ai_story, captions, reddit, roblox). One of `ai_story`, `captions`, `reddit`, `roblox`. |
| `title` | body | string | No |  | Project and file name. 1-120 chars. |
| `captionStyleId` | body | integer | No |  | Caption style id from list_caption_styles. Resets the font and outline to that style. 1-17. |
| `captionPosition` | body | number | No |  | Vertical position of the captions, 0 (top) to 100 (bottom). 0-100. |
| `captionSize` | body | number | No |  | Caption size, 0-100 (50 is the default). 0-100. |
| `textStyle` | body | object | No |  | Colour, case, outline and shadow over the caption style. |
| `backgroundVideoId` | body | string | No |  | Background clip id from list_background_videos. Up to 80 chars. |
| `backgroundGenre` | body | string | No |  | A list_background_videos category (e.g. "Minecraft"): picks a clip from it. Give this or backgroundVideoId. Up to 60 chars. |
| `bgStart` | body | integer | No |  | Where the background clip starts, in frames at 30 fps: 30 = 1 second, 300 = 10 seconds. 0-108000. |
| `musicId` | body | string | No |  | Background music id from list_music, or "none". Up to 80 chars. |
| `musicVolume` | body | number | No |  | Music volume, 0-100. 0-100. |
| `ratio` | body | string | No |  | Frame shape. One of `9:16`, `16:9`. |
| `flip` | body | string | No |  | Mirror the background clip. One of `none`, `horizontal`, `vertical`. |
| `captions` | body | object | No |  | Captions only: AI emojis on or off, and word fixes. |
| `reddit` | body | object | No |  | Reddit story only: the story card, its animation and the narration speed (instant); a new post title, story, voice or language regenerates the narration (charged, returns a job). |
| `roblox` | body | object | No |  | Roblox rant only: the narration (script, voiceId and language regenerate it and are charged; removeSilence and aiEmojis: true remake it for free), its speed and pitch. |
| `stills` | body | boolean | No |  | Default true: return fresh stills after the change (free, counts toward the preview limit). false skips them. |
| `dryRun` | body | boolean | No |  | Check the request and return { estimate } (credits and minutes) without spending anything. |
| `webhookUrl` | body | string (URL) | No |  | https URL that receives job.completed / job.failed, signed with your webhook secret. Up to 2048 chars. |
| `idempotencyKey` | body | string | No |  | Retry-safe key: repeating a call with the same key and input returns the first job instead of starting (and charging) again. REST callers can send the Idempotency-Key header instead. 1-255 chars. |

## Example

curl:

```bash
curl https://api.clippie.ai/v1/videos/PROJECT_ID \
  -H "Authorization: Bearer $CLIPPIE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
```

update-video.mjs:

```js
const auth = { Authorization: `Bearer ${process.env.CLIPPIE_API_KEY}` };

const res = await fetch('https://api.clippie.ai/v1/videos/PROJECT_ID', {
  method: 'POST',
  headers: { ...auth, 'Content-Type': 'application/json' },
  body: JSON.stringify({}),
});
if (!res.ok) throw new Error((await res.json()).error.message);
console.log(await res.json());
```

## Response

`200` with JSON. The full response schema is in the [OpenAPI spec](https://api.clippie.ai/v1/openapi.json).

## From an MCP client

Your AI calls `update_video` with the same fields as JSON arguments. See [MCP server](https://clippie.ai/developers/docs.md#mcp) to connect one.

tools/call:

```json
{
  "name": "update_video",
  "arguments": {
    "projectId": "PROJECT_ID"
  }
}
```
