> ## Documentation Index
> Fetch the complete documentation index at: https://docs.submagic.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Update Project

> Update an existing video project with new settings, features, or media insertions

# Update Project

Update an existing video project with new settings, AI features, or user media (B-roll) insertions. This endpoint allows you to modify project parameters and enhance your video with additional features or custom media content from your library.

<Note>
  This endpoint requires authentication and has a rate limit of 100 requests per
  hour. After modifying a video, you'll need to re-export to see the changes
  using the export endpoint. When using `removeBadTakes`, the response may take
  1-2 minutes as our AI processes the video.
</Note>

## Authentication

<ParamField header="x-api-key" type="string" required>
  Your Submagic API key starting with `sk-`
</ParamField>

## Path Parameters

<ParamField path="id" type="string" required>
  The unique identifier (UUID) of the project to update
</ParamField>

## Request Body

All fields are optional. Only provide the fields you want to update. If a field is provided with a different value from the current project settings, it will be updated.

<ParamField body="removeSilencePace" type="string">
  Automatically remove silence from the video at the specified pace. Allowed
  values: `natural`, `fast`, `extra-fast`. - `extra-fast`: 0.1-0.2 seconds of
  silence removal - `fast`: 0.2-0.6 seconds of silence removal - `natural`: 0.6+
  seconds of silence removal
</ParamField>

<ParamField body="removeBadTakes" type="boolean">
  Automatically detect and remove bad takes and silence from the video using AI
  analysis. **Note: This process may take 1-2 minutes to complete.**
</ParamField>

<ParamField body="disableCaptions" type="boolean">
  Hide captions from the exported video. Optional, defaults to `false`.
</ParamField>

<ParamField body="hookTitle" type="boolean | object">
  Update the animated hook caption shown at the start of the video. Set to
  `true` to enable the default AI-generated hook, `false` to remove it, or pass
  an object with optional overrides:

  * `text`: Custom copy (1-100 characters)
  * `template`: Hook title template name (defaults to `"tiktok"`). Fetch valid
    names using the [hook title templates
    endpoint](/api-reference/hook-title-templates).
  * `top`: Vertical position between 0-80 (default `50`)
  * `size`: Font size between 0-80 (default `30`)

  Template names are validated before processing resumes; invalid names return
  `VALIDATION_ERROR` immediately.
</ParamField>

<ParamField body="music" type="object">
  Optional background music track. When provided, replaces any existing
  background music on the project. The referenced media must be an `AUDIO` type
  file in your user media library.

  <Expandable title="Music Object" defaultOpen>
    <ParamField body="userMediaId" type="string" required>
      UUID of an audio file from your media library. Must reference a user media
      item with type `AUDIO`. Use the [List User Media](/api-reference/list-user-media)
      endpoint to find available audio files.
    </ParamField>

    <ParamField body="volume" type="number" required>
      Playback volume (1-100)
    </ParamField>

    <ParamField body="startFromTime" type="number">
      Start offset within the audio file in seconds. Defaults to `0`.
    </ParamField>

    <ParamField body="fade" type="boolean">
      Apply a fade-in/fade-out effect to the music track. Defaults to `true`.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="items" type="array">
  Array describing B-roll edits. Provide at least one entry when this field is
  included. Each item must include a `type` field to specify whether it's user
  media from your library or AI-generated content.

  <Expandable title="User Media Item" defaultOpen>
    <ParamField body="type" type="string" required>
      Must be set to `"user-media"`
    </ParamField>

    <ParamField body="startTime" type="number" required>
      Start time in seconds where the media should begin (must be ≥ 0)
    </ParamField>

    <ParamField body="endTime" type="number" required>
      End time in seconds where the media should end (must be greater than
      `startTime`)
    </ParamField>

    <ParamField body="userMediaId" type="string" required>
      UUID of the user media from your library. You can find this ID in the editor's 'B-roll' tab → 'My videos' section under each video.
    </ParamField>

    <ParamField body="layout" type="string">
      Layout mode for the inserted media. Available values depend on the media type:

      **Video media:** `"cover"`, `"contain"`, `"rounded"`, `"square"`, `"split-50-50"`, `"split-35-65"`, `"split-50-50-bordered"`, `"split-35-65-bordered"`, `"pip-top-right"`, `"pip-bottom-right"`

      **Image media:** `"cover"`, `"contain"`, `"rounded"`, `"square"`
    </ParamField>
  </Expandable>

  <Expandable title="AI B-roll Item" defaultOpen>
    <ParamField body="type" type="string" required>
      Must be set to `"ai-broll"`
    </ParamField>

    <ParamField body="startTime" type="number" required>
      Start time in seconds (must be ≥ 0)
    </ParamField>

    <ParamField body="endTime" type="number" required>
      End time in seconds. Must be greater than `startTime` and no more than 12
      seconds later.
    </ParamField>

    <ParamField body="prompt" type="string" required>
      1-2500 character description of what the AI should render. This field is
      mandatory whenever `type: "ai-broll"` is present.
    </ParamField>

    <ParamField body="layout" type="string">
      Layout mode for the AI B-roll. Allowed values: `"cover"`, `"contain"`, `"rounded"`, `"square"`, `"split-50-50"`, `"split-35-65"`, `"split-50-50-bordered"`, `"split-35-65-bordered"`, `"pip-top-right"`, `"pip-bottom-right"`
    </ParamField>
  </Expandable>

  **Important:** Each item must have a `type` field. Items entries cannot overlap
  each other in time.
</ParamField>

## AI B-roll Workflow & Credits

* Every AI B-roll item consumes **3 AI credits**. Requests fail with
  `VALIDATION_ERROR` if the authenticated user lacks enough credits (unless their
  balance is unlimited).
* When AI B-roll work is accepted, the project is moved back to `processing` and
  the generation jobs run asynchronously. Your webhook or polling logic should
  watch for the project to return to `completed`.
* Stock/user-media updates continue to succeed immediately with the traditional
  `Project updated successfully` message.

## Finding User Media ID

To find your `userMediaId`:

1. Go to the Submagic editor
2. Navigate to the **'B-roll'** tab
3. Add a B-roll to access your media library
4. Go to the **'My videos'** tab
5. Each video will display its unique media ID that you can use with this API

<img src="https://mintcdn.com/submagic/eEPiypbnZT0UxgbH/images/Example.png?fit=max&auto=format&n=eEPiypbnZT0UxgbH&q=85&s=34f0653da7f63c569ba15cf48d679871" alt="Example.png" width="2476" height="1768" data-path="images/Example.png" />

## Response

<ResponseField name="message" type="string">
  Success message confirming the project update. When AI B-roll work is accepted,
  the message is `Project update accepted` to indicate asynchronous rendering.
</ResponseField>

<ResponseField name="id" type="string">
  The unique identifier of the updated project
</ResponseField>

<ResponseField name="status" type="string">
  Updated processing status of the project. If AI B-roll generation was
  requested, the project is moved to `processing` until the renders finish.
</ResponseField>

## Error Responses

<ResponseField name="error" type="string">
  Error code: `NOT_FOUND` or `VALIDATION_ERROR`
</ResponseField>

<ResponseField name="message" type="string">
  Detailed error message explaining what went wrong
</ResponseField>

<ResponseField name="400 Invalid Hook Title Template" type="object">
  ```json theme={null}
  {
    "error": "VALIDATION_ERROR",
    "message": "Invalid template name"
  }
  ```
</ResponseField>

<RequestExample>
  ```bash cURL theme={null}
  curl -X PUT "https://api.submagic.co/v1/projects/550e8400-e29b-41d4-a716-446655440000" \
    -H "x-api-key: sk-your-api-key-here" \
    -H "Content-Type: application/json" \
    -d '{
      "removeSilencePace": "fast",
      "removeBadTakes": true,
      "hookTitle": {
        "text": "New intro in 15 seconds",
        "template": "laura",
        "top": 40,
        "size": 28
      },
      "music": {
        "userMediaId": "88a08eec-712a-45d0-8d0b-3b631700cb3a",
        "volume": 25,
        "startFromTime": 10,
        "fade": true
      },
      "items": [
        {
          "type": "user-media",
          "startTime": 10.5,
          "endTime": 15.2,
          "userMediaId": "123e4567-e89b-12d3-a456-426614174000",
          "layout": "pip-top-right"
        },
        {
          "type": "ai-broll",
          "startTime": 25,
          "endTime": 31,
          "prompt": "smooth slider shot of a team collaborating in a modern studio",
          "layout": "split-50-50"
        }
      ]
    }'
  ```

  ```javascript JavaScript theme={null}
  const updateProject = async (projectId, updateData) => {
    const response = await fetch(
      `https://api.submagic.co/v1/projects/${projectId}`,
      {
        method: "PUT",
        headers: {
          "x-api-key": "sk-your-api-key-here",
          "Content-Type": "application/json",
        },
        body: JSON.stringify(updateData),
      }
    );

    const result = await response.json();
    console.log("Project updated:", result.message);
    return result;
  };

  // Usage
  const updateData = {
    removeSilencePace: "fast",
    removeBadTakes: true,
    hookTitle: {
      text: "New intro in 15 seconds",
      template: "laura",
      top: 40,
      size: 28,
    },
    music: {
      userMediaId: "88a08eec-712a-45d0-8d0b-3b631700cb3a",
      volume: 25,
      startFromTime: 10,
      fade: true,
    },
    items: [
      {
        type: "user-media",
        startTime: 10.5,
        endTime: 15.2,
        userMediaId: "123e4567-e89b-12d3-a456-426614174000",
        layout: "pip-top-right",
      },
      {
        type: "ai-broll",
        startTime: 25,
        endTime: 31,
        prompt:
          "smooth slider shot of a team collaborating in a modern studio",
        layout: "split-50-50",
      },
    ],
  };

  const result = await updateProject(
    "550e8400-e29b-41d4-a716-446655440000",
    updateData
  );
  ```

  ```python Python theme={null}
  import json
  import requests

  def update_project(project_id, update_data):
      url = f'https://api.submagic.co/v1/projects/{project_id}'
      headers = {
          'x-api-key': 'sk-your-api-key-here',
          'Content-Type': 'application/json'
      }

      response = requests.put(url, headers=headers, json=update_data)
      result = response.json()

      print(f"Project updated: {result.get('message')}")
      return result

  # Usage
  update_data = {
      'removeSilencePace': 'fast',
      'removeBadTakes': True,
      'hookTitle': {
          'text': 'New intro in 15 seconds',
          'template': 'laura',
          'top': 40,
          'size': 28
      },
      'music': {
          'userMediaId': '88a08eec-712a-45d0-8d0b-3b631700cb3a',
          'volume': 25,
          'startFromTime': 10,
          'fade': True
      },
      'items': [
          {
              'type': 'user-media',
              'startTime': 10.5,
              'endTime': 15.2,
              'userMediaId': '123e4567-e89b-12d3-a456-426614174000',
              'layout': 'pip-top-right'
          },
          {
              'type': 'ai-broll',
              'startTime': 25,
              'endTime': 31,
              'prompt': 'smooth slider shot of a team collaborating in a modern studio',
              'layout': 'split-50-50'
          }
      ]
  }

  result = update_project('550e8400-e29b-41d4-a716-446655440000', update_data)
  ```
</RequestExample>

<ResponseExample>
  ```json 200 OK - Stock/User Media Only theme={null}
  {
    "message": "Project updated successfully",
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "processing"
  }
  ```

  ```json 200 OK - AI B-roll Accepted theme={null}
  {
    "message": "Project update accepted",
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "status": "processing"
  }
  ```

  ```json 404 NOT_FOUND theme={null}
  {
    "error": "NOT_FOUND",
    "message": "Project not found"
  }
  ```

  ```json 400 VALIDATION_ERROR - Invalid Time Range theme={null}
  {
    "error": "VALIDATION_ERROR",
    "message": "endTime must be greater than startTime"
  }
  ```

  ```json 400 VALIDATION_ERROR - Invalid UUID theme={null}
  {
    "error": "VALIDATION_ERROR",
    "message": "Invalid UUID format for userMediaId"
  }
  ```
</ResponseExample>

<Note>
  **Important:** After updating a project, you must re-export the project to see
  the changes in the final video. Use the export endpoint to generate the
  updated video with your modifications. **Processing Time:** When using
  `removeBadTakes`, the API response may take 1-2 minutes as our AI analyzes and
  processes the video to detect and remove bad takes and silence.
</Note>
