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

# Upload User Media

> Upload video or image files directly to your media library for use in projects

# Upload User Media

Upload video or image files directly to your user media library. This media can then be referenced in your video projects as custom B-roll using the returned `userMediaId`.

<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 (multipart/form-data)

<ParamField body="file" type="file" required>
  Video or image file to upload. Must be in a supported format.
</ParamField>

## Response

<ResponseField name="userMediaId" type="string">
  Unique identifier for the uploaded media (UUID format). Use this ID to
  reference the media in your video projects.
</ResponseField>

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST "https://api.submagic.co/v1/user-media/upload" \
    -H "x-api-key: sk-your-api-key-here" \
    -F "file=@./my-video.mp4"
  ```

  ```javascript JavaScript theme={null}
  const uploadUserMedia = async (file) => {
    const formData = new FormData();
    formData.append("file", file);

    const response = await fetch(
      "https://api.submagic.co/v1/user-media/upload",
      {
        method: "POST",
        headers: {
          "x-api-key": "sk-your-api-key-here",
        },
        body: formData,
      }
    );

    const data = await response.json();
    console.log("User media uploaded:", data.userMediaId);
    return data;
  };

  // Usage with file input
  const fileInput = document.getElementById("media-file");
  fileInput.addEventListener("change", async (event) => {
    const file = event.target.files[0];
    if (file) {
      await uploadUserMedia(file);
    }
  });
  ```

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

  def upload_user_media(file_path):
      url = 'https://api.submagic.co/v1/user-media/upload'
      headers = {
          'x-api-key': 'sk-your-api-key-here'
      }

      with open(file_path, 'rb') as media_file:
          files = {
              'file': media_file
          }

          response = requests.post(url, headers=headers, files=files)
          result = response.json()

          print(f"User media uploaded: {result['userMediaId']}")
          return result

  # Usage
  media = upload_user_media('./my-video.mp4')
  ```
</RequestExample>

<ResponseExample>
  ```json 201 Created theme={null}
  {
    "userMediaId": "88a08eec-712a-45d0-8d0b-3b631700cb7v"
  }
  ```
</ResponseExample>

## Using User Media in Projects

Once you have a `userMediaId`, you can reference it in the `items` array when creating or uploading projects:

```json theme={null}
{
  "items": [
    {
      "type": "user-media",
      "startTime": 5,
      "endTime": 10,
      "userMediaId": "88a08eec-712a-45d0-8d0b-3b631700cb3a"
    }
  ]
}
```

See the [Create Project](/api-reference/create-project) or [Upload Project](/api-reference/upload-project) documentation for more details on using user media in your videos.

## Error Responses

<ResponseField name="400 Validation Error" type="object">
  ```json theme={null}
  {
    "error": "VALIDATION_ERROR",
    "message": "File validation failed",
    "details": [
      {
        "field": "file",
        "message": "File is required",
        "value": null
      }
    ]
  }
  ```
</ResponseField>

<ResponseField name="400 Media Not Ready" type="object">
  ```json theme={null}
  {
    "error": "VALIDATION_ERROR",
    "message": "The following media is not ready yet: df7d8cfd-eb82-4865-8b32-df3396b972b1. Please wait for the upload to complete."
  }
  ```
</ResponseField>

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

<ResponseField name="413 Payload Too Large" type="object">
  ```json theme={null}
  {
    "error": "PAYLOAD_TOO_LARGE",
    "message": "File size exceeds maximum allowed size"
  }
  ```
</ResponseField>

<ResponseField name="415 Unsupported Media Type" type="object">
  ```json theme={null}
  {
    "error": "UNSUPPORTED_MEDIA_TYPE",
    "message": "Media format not supported"
  }
  ```
</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>
