# Upload a file

- **Method:** `POST`
- **Path:** `/v1/uploads`
- **Operation ID:** `createUpload`
- **Tags:** Uploads

Creates an upload link. PUT the file to `upload_url` with the same Content-Type within 2 hours, then pass `file_id` to another endpoint.

## Effective servers

- `https://api.vcp.name`

## Authentication

- **bearer**: HTTP bearer (`API key`)

  An API key from Settings, starting vcp\_live\_.

## Request body

**Required:** `true`

**Content type:** `application/json`

schema: `UploadBody`, no additional properties

- **`content_type` (required)**: `string`, possible values: `"audio/wav", "audio/x-wav", "audio/wave", "audio/vnd.wave", "audio/flac", "audio/x-flac", "audio/ogg", "audio/opus", "audio/mpeg", "image/jpeg", "image/png", "image/webp", "video/mp4", "video/quicktime", "video/x-matroska", "video/webm"`

  The file format. Send the same Content-Type when you upload the file.
- **`size` (required)**: `integer`, minimum: `1`, maximum: `2147483648`

  The file size in bytes. Audio can be up to 209715200 bytes, a photo up to 20971520 bytes and a video up to 2147483648 bytes.

**Example:**

```json
{
  "content_type": "video/mp4",
  "size": 284023112
}
```

## Responses

### 201 Created.

**Content type:** `application/json`

schema: `Upload`, no additional properties

- **`expires_at` (required)**: `string`, format: `date-time`

  When upload\_url stops working, 2 hours from now.
- **`file_id` (required)**: `string`

  Pass as audio\_file\_id, photo\_file\_id or video\_file\_id. The file is kept for 24 hours.
- **`upload_url` (required)**: `string`, format: `uri`

  PUT the file here.

**Example:**

```json
{
  "file_id": "8383fc02-625a-4b71-a226-cbb2d19aaf17",
  "upload_url": "https://files.example.com/upload/8383fc02-625a-4b71-a226-cbb2d19aaf17?token=abc",
  "expires_at": "2026-10-31T00:10:42Z"
}
```

### 400, 401, 403, 413, 429, 500, 503

- `400` The request is invalid. The message names the field.
- `401` The API key is missing, invalid or revoked.
- `403` The account needs a paid plan, or the action is not allowed.
- `413` The request is too large.
- `429` Too many requests. Retry after the Retry-After header.
- `500` Something went wrong on our side.
- `503` Temporarily unavailable. Retry after the Retry-After header.

**Content type:** `application/json`

schema: `ErrorBody`, no additional properties

- **`error` (required)**: `object`, schema: `ErrorDetail`, no additional properties
  - **`code` (required)**: `string`

    A code from the error tables.
  - **`message` (required)**: `string`

    What went wrong.
  - **`param`**: `string`

    The request field at fault, when there is one.

**Example:**

```json
{
  "error": {
    "code": "invalid_request",
    "message": "text is required.",
    "param": "text"
  }
}
```

## Schemas

### ErrorBody

**Type:** `object`, no additional properties

*Schema `ErrorBody` is shown above.*

**Example:**

```json
{
  "error": {
    "code": "invalid_request",
    "message": "text is required.",
    "param": "text"
  }
}
```

- `ErrorDetail` — shown above.
- `UploadBody` — shown above.
- `Upload` — shown above.
