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

# Start Multipart Upload

> Upload videos up to 500 MB in resumable parts, then finalize them into the Genviral Media Library.

Use a multipart upload for videos larger than 100 MB, such as phone footage (a minute of 4K is
about 350 MB). Each part is an independent PUT, so a dropped connection resends one part instead
of the whole file. Nothing appears in the Media Library until
[Complete Multipart Upload](/api-reference/complete-multipart-upload) verifies the bytes.

## How It Works

1. Call this endpoint with the content type, exact byte `size`, and a stable `Idempotency-Key`.
2. Split the file into `partSize` chunks (16 MiB). PUT chunk *n* to `parts[n-1].uploadUrl`. The
   last part carries the remainder. Each URL accepts exactly its part's length.
3. Keep the `ETag` response header of every part PUT.
4. Call [Complete Multipart Upload](/api-reference/complete-multipart-upload) with every
   `partNumber` and its `etag`.

Part URLs must be started within `expiresIn` seconds (one hour). To resume later, call this
endpoint again with the same `Idempotency-Key` and body: you get the same upload `id` and
`uploadId` with fresh part URLs. Re-PUT only the parts that did not finish.

## Body Parameters

<ParamField body="contentType" type="string" required>
  MIME type of the file. Videos: `video/mp4`, `video/quicktime`, `video/x-msvideo`,
  `video/webm`, `video/x-m4v`. Images are accepted too, up to 50 MB.
</ParamField>

<ParamField body="size" type="integer" required>
  Exact byte size of the file: at most 524,288,000 (500 MB) for videos and 52,428,800 (50 MB)
  for images.
</ParamField>

<ParamField body="filename" type="string">
  Original filename, used for display.
</ParamField>

## Response

Successful requests return `201` with:

* `id` - upload identity, used to complete or abort the upload
* `uploadId` - multipart upload identity
* `partSize` - bytes per part (16,777,216); the last part carries the remainder
* `parts` - `{ partNumber, uploadUrl }` for every part, in order
* `expiresIn` - seconds the part URLs can be started (3600)

<ResponseExample>
  ```json Response theme={null}
  {
    "ok": true,
    "code": 201,
    "message": "Multipart upload started",
    "data": {
      "id": "11111111-1111-4111-8111-111111111111",
      "uploadId": "2~example-upload-id",
      "partSize": 16777216,
      "parts": [
        { "partNumber": 1, "uploadUrl": "https://storage.example.com/presigned-part-1..." },
        { "partNumber": 2, "uploadUrl": "https://storage.example.com/presigned-part-2..." }
      ],
      "expiresIn": 3600
    }
  }
  ```
</ResponseExample>

## Error Responses

* `400 invalid_request` - `Idempotency-Key` is missing or invalid
* `400 upload_failed` - the `Idempotency-Key` was already used with a different body
* `422 invalid_payload` - unsupported content type, or `size` above the limit for its media type


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.