> ## 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.

# Create Project

> Create a new video project using a video URL for AI-powered caption generation

# Create Project

Create a new video project by providing a video URL. This endpoint will download the video, transcribe the audio, and apply the specified template with AI-generated captions and effects.

<Note>
  This endpoint requires authentication and has a rate limit of 500 requests per
  hour.
</Note>

## Authentication

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

## Request Body

<ParamField body="title" type="string" required>
  A descriptive title for your video project (1-100 characters)
</ParamField>

<ParamField body="language" type="string" required>
  Language code for transcription (e.g., "en", "es", "fr"). Use the [languages
  endpoint](/api-reference/languages) to get available options.
</ParamField>

<ParamField body="videoUrl" type="string" required>
  Public URL to your video file. Must be accessible without authentication and
  in a supported format.
</ParamField>

<ParamField body="aiEditTemplate" type="string">
  Name of an AI edit template to apply. AI edit templates automatically apply
  AI-powered scene splitting, B-roll, music, and styling to your video. Available templates: `"kelly"` (minimal, design), `"karl"`
  (effective, modern), `"ella"` (dynamic, bold).

  When `aiEditTemplate` is provided, the only other fields you can pass
  alongside it are `title`, `language`, `videoUrl`, `webhookUrl`, and
  `dictionary`. All other fields will be ignored or rejected.
</ParamField>

<ParamField body="presetId" type="string">
  ID of a saved preset to apply to the project. A preset is a snapshot of your
  project settings — including captions style, hook title, music, effects, and
  more. When provided, all preset settings are automatically applied after
  transcription completes. To get your preset ID, go to the Presets page in the
  app, open the dropdown menu on any preset card, and click **"Copy ID"**.

  Cannot be combined with `templateName`, `userThemeId`, `hookTitle`, `music`,
  `items`, `magicZooms`, `magicBrolls`, `magicBrollsPercentage`,
  `removeSilencePace`, or `removeBadTakes` — the preset already controls these
  settings.
</ParamField>

<ParamField body="templateName" type="string">
  Template to apply for styling. Use the [templates
  endpoint](/api-reference/templates) to get available options. Defaults to
  "Sara" if not specified. Cannot be used together with `userThemeId`.
</ParamField>

<ParamField body="userThemeId" type="string">
  ID of a custom user theme to apply for styling. Must be a valid UUID of a
  theme that belongs to you or your team. Cannot be used together with
  `templateName`. You can find the id of your custom theme by opening a project,
  selecting the theme, pressing the pen icon to edit it. You'll see the id of
  the theme under theme's name.
</ParamField>

<ParamField body="hookTitle" type="boolean | object">
  Adds an animated opening caption (hook) to the video. Set to `true` to let AI
  generate using the default style or pass an object to customize the
  appearance:

  * `text` (optional): Custom hook, 1-100 characters
  * `template` (optional): Hook title template name. Defaults to `"tiktok"`.
    Use the [hook title templates
    endpoint](/api-reference/hook-title-templates) to retrieve valid options.
  * `top` (optional): Vertical position (0-80). Defaults to `50`.
  * `size` (optional): Font size (0-80). Defaults to `30`.
</ParamField>

<ParamField body="webhookUrl" type="string">
  URL to receive webhook notifications when processing is complete. Must be a
  valid HTTPS URL.
</ParamField>

<ParamField body="dictionary" type="array">
  Array of custom words or phrases to improve transcription accuracy (max 100
  items, 50 characters each).
</ParamField>

<ParamField body="items" type="array">
  Optional array of items to insert into the video. 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 timestamp in seconds (must be ≥ 0)
    </ParamField>

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

    <ParamField body="prompt" type="string" required>
      Describes what the AI B-roll should depict (1-2500 characters)
    </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 cannot overlap with
  each other in time. Requests that include invalid durations, overlapping
  ranges, or prompts outside the allowed length will be rejected.
</ParamField>

<ParamField body="magicZooms" type="boolean">
  Enable automatic zoom effects on the video to enhance visual engagement.
  Optional, defaults to false.
</ParamField>

<ParamField body="magicBrolls" type="boolean">
  Enable automatic B-roll insertion to enhance video content with relevant
  supplementary footage. Optional, defaults to false.
</ParamField>

<ParamField body="magicBrollsPercentage" type="number">
  Percentage of automatic B-rolls to include in the video (0-100). Only
  effective when magicBrolls is enabled. Optional, defaults to 50.
</ParamField>

<ParamField body="removeSilencePace" type="string">
  Automatically remove silence from the video at the specified pace. Optional.
  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. Optional, defaults to false.
</ParamField>

<ParamField body="cleanAudio" type="boolean">
  Enable AI-powered audio cleanup that removes background noises from the video.
  Optional, defaults to false.
</ParamField>

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

<ParamField body="music" type="object">
  Optional background music track that spans the full project duration. 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>

## Supported Formats & Limits

<CardGroup cols={2}>
  <Card title="Supported Formats" icon="video">
    * **MP4** (.mp4) - **MOV** (.mov)
  </Card>

  <Card title="File Limits" icon="upload">
    * **Max size:** 2GB - **Max duration:** 2 hours
  </Card>
</CardGroup>

## Response

<ResponseField name="id" type="string">
  Unique identifier for the created project (UUID format)
</ResponseField>

<ResponseField name="title" type="string">
  The title you provided for the project
</ResponseField>

<ResponseField name="language" type="string">
  Language code used for transcription
</ResponseField>

<ResponseField name="status" type="string">
  Current processing status: `processing`, `transcribing`, `exporting`,
  `completed`, or `failed`
</ResponseField>

<ResponseField name="webhookUrl" type="string">
  Webhook URL if provided in the request
</ResponseField>

<ResponseField name="templateName" type="string">
  Template name applied to the project
</ResponseField>

<ResponseField name="userThemeId" type="string">
  User theme ID applied to the project
</ResponseField>

<ResponseField name="presetId" type="string">
  Preset ID applied to the project
</ResponseField>

<ResponseField name="aiEditTemplate" type="string">
  AI edit template applied to the project (if any): `kelly`, `karl`, or `ella`
</ResponseField>

<ResponseField name="magicZooms" type="boolean">
  Whether automatic zoom effects are enabled for the video
</ResponseField>

<ResponseField name="magicBrolls" type="boolean">
  Whether automatic B-roll insertion is enabled for the video
</ResponseField>

<ResponseField name="magicBrollsPercentage" type="number">
  Percentage of automatic B-rolls to include in the video (0-100)
</ResponseField>

<ResponseField name="removeSilencePace" type="string">
  Pace setting for automatic silence removal: `natural`, `fast`, or `extra-fast`
</ResponseField>

<ResponseField name="removeBadTakes" type="boolean">
  Whether automatic bad takes and silence removal is enabled
</ResponseField>

<ResponseField name="cleanAudio" type="boolean">
  Whether AI-powered audio cleanup is enabled
</ResponseField>

<ResponseField name="createdAt" type="string">
  ISO 8601 timestamp when the project was created
</ResponseField>

<ResponseField name="updatedAt" type="string">
  ISO 8601 timestamp when the project was last updated
</ResponseField>

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST "https://api.submagic.co/v1/projects" \
    -H "x-api-key: sk-your-api-key-here" \
    -H "Content-Type: application/json" \
    -d '{
      "title": "My Awesome Video",
      "language": "en",
      "videoUrl": "https://example.com/videos/sample.mp4",
      "templateName": "Hormozi 2",
      "items": [
        {
          "type": "user-media",
          "startTime": 5,
          "endTime": 10,
          "userMediaId": "123e4567-e89b-12d3-a456-426614174000",
          "layout": "pip-top-right"
        },
        {
          "type": "ai-broll",
          "startTime": 15,
          "endTime": 21,
          "prompt": "person performing multiple back exercises on gym equipment",
          "layout": "split-50-50"
        }
      ],
      "webhookUrl": "https://yoursite.com/webhook/submagic",
      "dictionary": ["Submagic", "AI-powered", "captions"],
      "magicZooms": true,
      "magicBrolls": true,
      "magicBrollsPercentage": 75,
      "removeSilencePace": "fast",
      "removeBadTakes": true,
      "cleanAudio": true,
      "hookTitle": {
        "text": "Stop scrolling—watch this in 30 seconds",
        "template": "tiktok",
        "top": 45,
        "size": 32
      },
      "music": {
        "userMediaId": "88a08eec-712a-45d0-8d0b-3b631700cb3a",
        "volume": 30,
        "startFromTime": 0,
        "fade": true
      }
    }'
  ```

  ```javascript JavaScript theme={null}
  const createProject = async () => {
    const response = await fetch("https://api.submagic.co/v1/projects", {
      method: "POST",
      headers: {
        "x-api-key": "sk-your-api-key-here",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        title: "My Awesome Video",
        language: "en",
        videoUrl: "https://example.com/videos/sample.mp4",
        templateName: "Hormozi 2",
        items: [
          {
            type: "user-media",
            startTime: 5,
            endTime: 10,
            userMediaId: "123e4567-e89b-12d3-a456-426614174000",
            layout: "pip-top-right",
          },
          {
            type: "ai-broll",
            startTime: 15,
            endTime: 21,
            prompt:
              "person performing multiple back exercises on gym equipment",
            layout: "split-50-50",
          },
        ],
        webhookUrl: "https://yoursite.com/webhook/submagic",
        dictionary: ["Submagic", "AI-powered", "captions"],
        magicZooms: true,
        magicBrolls: true,
        magicBrollsPercentage: 75,
        removeSilencePace: "fast",
        removeBadTakes: true,
        cleanAudio: true,
        hookTitle: {
          text: "Stop scrolling—watch this in 30 seconds",
          template: "tiktok",
          top: 45,
          size: 32,
        },
        music: {
          userMediaId: "88a08eec-712a-45d0-8d0b-3b631700cb3a",
          volume: 30,
          startFromTime: 0,
          fade: true,
        },
      }),
    });

    const project = await response.json();
    console.log("Project created:", project.id);
    return project;
  };
  ```

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

  def create_project():
      url = 'https://api.submagic.co/v1/projects'
      headers = {
          'x-api-key': 'sk-your-api-key-here',
          'Content-Type': 'application/json'
      }
      data = {
          'title': 'My Awesome Video',
          'language': 'en',
          'videoUrl': 'https://example.com/videos/sample.mp4',
          'templateName': 'Hormozi 2',
          'items': [
              {
                  'type': 'user-media',
                  'startTime': 5,
                  'endTime': 10,
                  'userMediaId': '123e4567-e89b-12d3-a456-426614174000',
                  'layout': 'pip-top-right'
              },
              {
                  'type': 'ai-broll',
                  'startTime': 15,
                  'endTime': 21,
                  'prompt': 'person performing multiple back exercises on gym equipment',
                  'layout': 'split-50-50'
              }
          ],
          'webhookUrl': 'https://yoursite.com/webhook/submagic',
          'dictionary': ['Submagic', 'AI-powered', 'captions'],
          'magicZooms': True,
          'magicBrolls': True,
          'magicBrollsPercentage': 75,
          'removeSilencePace': 'fast',
          'removeBadTakes': True,
          'cleanAudio': True,
          'hookTitle': {
              'text': 'Stop scrolling—watch this in 30 seconds',
              'template': 'tiktok',
              'top': 45,
              'size': 32
          },
          'music': {
              'userMediaId': '88a08eec-712a-45d0-8d0b-3b631700cb3a',
              'volume': 30,
              'startFromTime': 0,
              'fade': True
          }
      }

      response = requests.post(url, headers=headers, json=data)
      project = response.json()

      print(f"Project created: {project['id']}")
      return project
  ```
</RequestExample>

<ResponseExample>
  ```json 201 Created theme={null}
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "title": "My Awesome Video",
    "language": "en",
    "status": "processing",
    "webhookUrl": "https://yoursite.com/webhook/submagic",
    "templateName": "Hormozi 2",
    "magicZooms": true,
    "magicBrolls": true,
    "magicBrollsPercentage": 75,
    "removeSilencePace": "fast",
    "removeBadTakes": true,
    "cleanAudio": true,
    "createdAt": "2024-01-15T10:30:00.000Z",
    "updatedAt": "2024-01-15T10:30:00.000Z"
  }
  ```
</ResponseExample>

## Custom Dictionary

Improve transcription accuracy by providing custom terms:

```json theme={null}
{
  "dictionary": [
    "Submagic",
    "API endpoint",
    "captions",
    "transcription",
    "AI-powered",
    "webhook notification"
  ]
}
```

**Best practices for dictionary terms:**

* Include brand names, product names, or technical terms
* Add words that are frequently mispronounced or misunderstood
* Keep terms under 50 characters each
* Limit to 100 terms per project

## Webhook Integration

Receive notifications when your project is complete:

```json theme={null}
{
  "webhookUrl": "https://yoursite.com/webhook/submagic"
}
```

Your webhook endpoint will receive a POST request:

```json theme={null}
{
  "projectId": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "downloadUrl": "https://app.submagic.co/api/file/download?path=3c6cd7cd-3f5e-4def-b662-69c48a7fc8ce/e568c322-7fa5-497a-8fb0-3ba32e9e67d2/364fe092-b68d-468a-9558-bfca7c4d130e-download.mp4&newFileName=ProMotion%20Display%20Breakthrough.mp4",
  "directUrl": "https://dqu1p08d61fh.cloudfront.net/api/9cc52d00-43d7-442f-9a22-050312bkm24f/1ddee5b4-101f-4c1e-a74a-b6b3bcfe206c/video.mp4-download.mp4",
  "timestamp": "2024-01-15T10:45:00.000Z"
}
```

## Error Responses

<ResponseField name="400 Validation Error" type="object">
  ```json theme={null}
  {
    "error": "VALIDATION_ERROR",
    "message": "Request validation failed",
    "details": [
      {
        "field": "videoUrl",
        "message": "Must be a valid URL",
        "value": "invalid-url"
      }
    ]
  }
  ```
</ResponseField>

<ResponseField name="400 Preset Conflict" type="object">
  ```json theme={null}
  {
    "error": "VALIDATION_ERROR",
    "message": "presetId cannot be combined with templateName, userThemeId, magicZooms, magicBrolls, magicBrollsPercentage, removeBadTakes, removeSilencePace, items, hookTitle, or music. The preset controls these settings."
  }
  ```
</ResponseField>

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

<ResponseField name="400 Unsupported Social Media URL" type="object">
  ```json theme={null}
  {
    "error": "VALIDATION_ERROR",
    "message": "URLs from social media platforms are not supported. Please use a direct download link."
  }
  ```
</ResponseField>

<ResponseField name="401 Unauthorized" type="object">
  ```json theme={null}
  {
    "error": "UNAUTHORIZED",
    "message": "Invalid or missing API key"
  }
  ```
</ResponseField>

<ResponseField name="429 Rate Limited" type="object">
  ```json theme={null}
  {
    "error": "RATE_LIMIT_EXCEEDED",
    "message": "Too many requests",
    "retryAfter": 30
  }
  ```
</ResponseField>

<ResponseField name="500 Server Error" type="object">
  ```json theme={null}
  {
    "error": "INTERNAL_SERVER_ERROR", 
    "message": "An unexpected error occurred"
  }
  ```
</ResponseField>
