YouTube
Connect a YouTube account and upload videos through the PostZen API.
PostZen publishes videos to YouTube through a connected account. YouTube is video-only: every post must contain exactly one video, a title, and a privacyStatus setting.
YouTube uploads have a hard 2 GB cap. PostZen rejects larger videos.
Quick reference
| Requirement | YouTube value |
|---|---|
| Content type | Video only |
| Media per post | Exactly 1 video |
| Title | Required; up to 100 characters; cannot contain < or > |
Description (content) | Up to 5,000 characters |
| Privacy | privacyStatus is required: public, unlisted, or private |
| Tags | String array or comma-separated string; up to 500 characters when joined |
| Video formats accepted by PostZen | MP4, MPEG, QuickTime, AVI, WebM, M4V |
| Maximum video size | 2 GB hard cap |
| Scheduling | Supported |
Before you start
- Create a PostZen profile and keep its
_idas yourprofileId. - Connect the YouTube account through Google OAuth 2.0. PostZen manages the video-upload and read-only channel scopes internally.
- The free tier supports up to 2 connected accounts before a payment method is required. Connecting another account returns a
402until you add one. - Prepare exactly one video no larger than 2 GB. Images are not supported for YouTube posts.
- Set both a title and
privacyStatuson every upload. The title can come fromsettings.titleor fall back to the post's top-leveltitle.
Cloud-storage share links from Google Drive, Dropbox, OneDrive, and iCloud return HTML pages instead of media files. Use a publicly accessible direct video URL, or upload the file through /v1/media/presign and pass the returned publicUrl in mediaItems.
Connect your account
Request a YouTube connect URL for your profile, then send the user to the returned authUrl. The OAuth state expires after 10 minutes.
const { data } = await postzen.connect.createConnectUrl({
path: { platform: 'youtube' },
query: {
profileId: 'jh72r5nqk9wx3v8m1t4cz6bs0fy5dg3e',
redirectUrl: 'https://yourapp.com/connected',
},
});
console.log(data.authUrl); // redirect the user here
console.log(data.state); // expires after 10 minutesresponse = client.connect.create_connect_url(
"youtube",
profile_id="jh72r5nqk9wx3v8m1t4cz6bs0fy5dg3e",
redirect_url="https://yourapp.com/connected",
)
print(response.authUrl) # redirect the user here
print(response.state) # expires after 10 minutescurl "https://api.postzen.dev/v1/connect/youtube?profileId=jh72r5nqk9wx3v8m1t4cz6bs0fy5dg3e&redirectUrl=https://yourapp.com/connected" \
-H "Authorization: Bearer $POSTZEN_API_KEY"The response is { authUrl, state }. Complete the Google OAuth flow at authUrl before the state expires.
Quick start
Upload one video by passing its direct URL or PostZen publicUrl in mediaItems. The example sets publishNow and all six YouTube settings.
const { data } = await postzen.posts.createPost({
body: {
content: 'A walkthrough of our latest release.',
publishNow: true,
mediaItems: [
{ url: 'https://cdn.example.com/product-walkthrough.mp4' },
],
platforms: [
{
platform: 'youtube',
accountId: 'jh72r5nqk9wx3v8m1t4cz6bs0fy5dg3e',
settings: {
title: 'Product walkthrough',
privacyStatus: 'public',
tags: ['product', 'walkthrough'],
categoryId: '22',
madeForKids: false,
notifySubscribers: true,
},
},
],
},
});
console.log(data.post._id);response = client.posts.create_post(
content="A walkthrough of our latest release.",
publish_now=True,
media_items=[
{"url": "https://cdn.example.com/product-walkthrough.mp4"},
],
platforms=[
{
"platform": "youtube",
"account_id": "jh72r5nqk9wx3v8m1t4cz6bs0fy5dg3e",
"settings": {
"title": "Product walkthrough",
"privacy_status": "public",
"tags": ["product", "walkthrough"],
"category_id": "22",
"made_for_kids": False,
"notify_subscribers": True,
},
},
],
)
print(response.post.field_id)curl -X POST https://api.postzen.dev/v1/posts \
-H "Authorization: Bearer $POSTZEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "A walkthrough of our latest release.",
"publishNow": true,
"mediaItems": [
{ "url": "https://cdn.example.com/product-walkthrough.mp4" }
],
"platforms": [
{
"platform": "youtube",
"accountId": "jh72r5nqk9wx3v8m1t4cz6bs0fy5dg3e",
"settings": {
"title": "Product walkthrough",
"privacyStatus": "public",
"tags": ["product", "walkthrough"],
"categoryId": "22",
"madeForKids": false,
"notifySubscribers": true
}
}
]
}'To schedule the upload, replace publishNow with an ISO-8601 scheduledFor timestamp at least 60 seconds in the future. Set exactly one of publishNow, scheduledFor, or isDraft.
Content types
Video uploads
YouTube posts require exactly one video. The post's content becomes the video description, while YouTube-specific fields belong in the target's settings object.
{
content: 'Video description',
mediaItems: [{ url: 'https://cdn.example.com/video.mp4' }],
platforms: [
{
platform: 'youtube',
accountId: 'jh72r5nqk9wx3v8m1t4cz6bs0fy5dg3e',
settings: { title: 'Video title', privacyStatus: 'unlisted' },
},
],
}YouTube may classify vertical 9:16 videos up to about 3 minutes as Shorts. YouTube makes that classification; PostZen does not provide a Shorts setting.
Media requirements
Images
| Requirement | Value |
|---|---|
| Supported | No |
| Behavior | Attaching an image causes an error because YouTube posts are video-only. |
Videos
| Requirement | Value |
|---|---|
| Count | Exactly 1 video per post |
| Formats accepted by PostZen | MP4, MPEG, QuickTime, AVI, WebM, M4V |
| Maximum file size | 2 GB hard cap; larger videos are rejected |
| Description | Up to 5,000 characters in content |
| Title | Required; up to 100 characters; cannot contain < or > |
External media URLs can be up to 100 MB before PostZen downloads and re-hosts them. For larger files within YouTube's 2 GB cap, request a presigned upload URL from /v1/media/presign, upload the file, and use the returned publicUrl.
Platform settings
Pass these keys inside the YouTube target's settings object:
| Setting | Type | Notes |
|---|---|---|
title | string | Required unless the post has a top-level title; up to 100 characters; cannot contain < or > |
privacyStatus | "public" | "unlisted" | "private" | Required |
tags | string[] or comma-separated string | Up to 500 characters when joined |
categoryId | string | YouTube category ID; for example, "22" is People & Blogs |
madeForKids | boolean | Flags the video as made for kids |
notifySubscribers | boolean | Controls whether subscribers get an upload notification |
platforms: [
{
platform: 'youtube',
accountId: 'jh72r5nqk9wx3v8m1t4cz6bs0fy5dg3e',
settings: {
title: 'Product walkthrough',
privacyStatus: 'public',
tags: ['product', 'walkthrough'],
categoryId: '22',
madeForKids: false,
notifySubscribers: true,
},
},
]PostZen analytics is live for YouTube, including view, like, and comment counts for your own videos, your subscriber count, and best-time-to-post suggestions. Shares, saves, and impressions are not reported by the YouTube Data API, and channels that hide their subscriber count show no follower total.
What you can't do
- PostZen does not support image posts or community posts on YouTube.
- PostZen does not yet support custom thumbnails.
- PostZen does not support playlists, premieres, or live streams.
- PostZen does not support uploading captions or subtitles, or configuring end screens, cards, or chapters.
- PostZen does not support monetization settings or editing a published video.
- PostZen does not provide DMs or an inbox, comment management, ads, or engagement webhooks.
Common errors
| Error | Meaning | Fix |
|---|---|---|
Missing title or privacyStatus | Both fields are required for a YouTube upload. | Set settings.title or a top-level title, and set settings.privacyStatus to public, unlisted, or private. |
| Invalid title | The title is over 100 characters or contains < or >. | Shorten the title and remove < and >. |
| Video over 2 GB | The video exceeds PostZen's hard 2 GB cap for YouTube. | Upload a video no larger than 2 GB. |
| Image attached | YouTube posts are video-only. | Remove the image and attach exactly one video. |
402 while connecting | The free-tier account limit has been reached and no payment method is on file. | Add a payment method, then start the connect flow again. |
| OAuth state expired | More than 10 minutes passed after PostZen created the connect URL. | Request a new connect URL and complete OAuth within 10 minutes. |