# Upload YouTube file

> Upload a YouTube video as a multipart file.

Canonical: <https://www.tryadeli.com/docs/api/posts/upload-youtube-video-file>

`POST https://app.tryadeli.com/api/v1/posts/youtube`

Authorization: `Bearer <API key>` — see [Authentication](https://www.tryadeli.com/docs/authentication)

[`POST /api/v1/posts`](https://www.tryadeli.com/docs/api/posts/publish-youtube) takes multipart for TikTok only, so a YouTube file upload
has its own route. Fields use the same names; booleans are the strings
`"true"` or `"false"`, and `tags` is comma-separated. Send one `video` file of
up to 4 GiB and, optionally, a `thumbnail` (JPEG or PNG, up to 50 MB).
YouTube allows custom thumbnails only on verified channels; a refused thumbnail
is a warning, not a failed upload.

It returns `202` once YouTube has the file, with the same response as
[Publish to YouTube](https://www.tryadeli.com/docs/api/posts/publish-youtube). Processing continues
after; poll [YouTube upload status](https://www.tryadeli.com/docs/api/posts/get-youtube-upload-status).

## Request examples

**cURL**

```bash
curl --fail-with-body -X POST "https://app.tryadeli.com/api/v1/posts/youtube" \
  -H "Authorization: Bearer $ADELI_API_KEY" \
  -F 'platform=youtube' \
  -F 'accountId=00000000-0000-0000-0000-000000000000' \
  -F 'title=Heron fishing at dawn' \
  -F 'privacy_status=unlisted' \
  -F 'made_for_kids=false' \
  -F 'tags=birds,herons' \
  -F "video=@heron.mp4;type=video/mp4" \
  -F "thumbnail=@heron.jpg;type=image/jpeg"
```

**JavaScript**

```javascript
import { openAsBlob } from "node:fs";

const form = new FormData();
form.append("platform", "youtube");
form.append("accountId", "00000000-0000-0000-0000-000000000000");
form.append("title", "Heron fishing at dawn");
form.append("privacy_status", "unlisted");
form.append("made_for_kids", "false");
form.append("tags", "birds,herons");
form.append("video", await openAsBlob("heron.mp4", { type: "video/mp4" }), "heron.mp4");
form.append("thumbnail", await openAsBlob("heron.jpg", { type: "image/jpeg" }), "heron.jpg");

const response = await fetch("https://app.tryadeli.com/api/v1/posts/youtube", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.ADELI_API_KEY}`,
  },
  body: form,
});
console.log(await response.json());
```

**Python**

```python
import os

import requests

response = requests.post(
    "https://app.tryadeli.com/api/v1/posts/youtube",
    headers={"Authorization": f"Bearer {os.environ['ADELI_API_KEY']}"},
    data={
        "platform": "youtube",
        "accountId": "00000000-0000-0000-0000-000000000000",
        "title": "Heron fishing at dawn",
        "privacy_status": "unlisted",
        "made_for_kids": "false",
        "tags": "birds,herons",
    },
    files={
        "video": ("heron.mp4", open("heron.mp4", "rb"), "video/mp4"),
        "thumbnail": ("heron.jpg", open("heron.jpg", "rb"), "image/jpeg"),
    },
)
print(response.json())
```

## Responses

### 202

```json
{
  "id": "youtube_post_00000000-0000-0000-0000-000000000000_dQw4w9WgXcQ",
  "platform": "youtube",
  "accountId": "00000000-0000-0000-0000-000000000000",
  "profileId": "00000000-0000-4000-8000-000000000001",
  "publishId": "dQw4w9WgXcQ",
  "videoId": "dQw4w9WgXcQ",
  "permalink": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  "status": "ACCEPTED",
  "requestedPrivacy": "unlisted",
  "appliedPrivacy": "private",
  "privacyRestricted": true,
  "publishAt": null,
  "thumbnail": "set",
  "statusUrl": "/api/v1/posts/youtube/status?accountId=...&profileId=...&videoId=dQw4w9WgXcQ",
  "warnings": [
    { "code": "privacy_restricted", "message": "YouTube locked this upload to private: the app has not yet passed the YouTube API Services audit" }
  ]
}
```

### 429

```json
{
  "error": {
    "code": "quota_exhausted",
    "message": "YouTube's daily API quota is used up; it resets at 2026-10-10T07:00:00.000Z"
  }
}
```
