---
title: "Start a resumable upload (up to 2 GB)"
method: POST
path: "/v1/uploads"
tags: ["Files"]
---

# Start a resumable upload (up to 2 GB)

`POST /v1/uploads`

## Request

- Base URL: `https://contentmaschine.ai/api`
- URL: `https://contentmaschine.ai/api/v1/uploads`
- Auth: one of:
  - HTTP bearer
  - OAuth 2 (authorization code, authorization URL `https://contentmaschine.ai/api/oauth/authorize`, token URL `https://contentmaschine.ai/api/oauth/token`)

The file goes straight to object storage in parts of `part_size` bytes (8 MB; the last
part is smaller). Then: ask for part URLs with POST /v1/uploads/{uuid}/parts, PUT each
part to its URL and keep the `ETag` response header, then POST /v1/uploads/{uuid}/complete.
An unfinished upload expires after 24 hours.

With `sha256` of a file already in your library, nothing is uploaded: `upload_id` is
null and `existing_file_uuid` names that file.

Types: video/mp4, video/quicktime, video/webm, video/x-matroska, video/mpeg, audio/mpeg, audio/wav, audio/mp4, audio/aac, audio/ogg, audio/webm, audio/flac, image/png, image/jpeg, image/webp, image/gif. Images up to
25 MB, video and audio up to 2 GB. After completion the content is
checked; a file that is not what it claims is deleted and the upload fails.

## Request body

- object
  - `filename` string, required: Display name of the file.
  - `size` integer, required: Size in bytes.
  - `mime_type` string: The file type. Empty: taken from the file extension.
  - `sha256` string: Optional hex digest, for dedupe against your library.
  - `purpose` 'library' | 'transcription' | 'studio' | 'studio_export': What the file is for.

## Response `201`

The upload, or the existing file.

- object
  - `success` boolean
  - `data` object
    - `upload_id` string, uuid, nullable
    - `part_size` integer: Bytes per part.
    - `parts` integer: Number of parts.
    - `expires_at` string, date-time
    - `existing_file_uuid` string, uuid: Only when sha256 matched a file you already have.
  - `timestamp` string, date-time

## Other responses

- `400`: Invalid filename, size, sha256 or purpose.
- `401`: Missing or invalid API key.
- `403`: The token does not hold files:write.
- `413`: File too large for its type.
- `415`: Unsupported file type.
- `429`: Too many uploads in progress, or the daily upload limit.
- `503`: Uploads are not available right now.
- `default`: Any other error. Every failure this API emits uses the same envelope; branch on `error.type`, never on `error.message`, and quote `error.correlation_id` to support.

---

[API](https://skmtc.dev/contentmaschine/apis/contentmaschine-ai-api.md) · [All operations](https://skmtc.dev/contentmaschine/apis/contentmaschine-ai-api/llms.txt) · [OpenAPI document](https://skmtc.dev/contentmaschine/apis/contentmaschine-ai-api/revisions/28c74f46051c?raw)
