Publishing to YouTube via API: A technical guide

Understanding OAuth setup, the resumable upload protocol, video metadata, processing status, and quota costs for YouTube video publishing.

Publishing to YouTube via API: A technical guide

Before you start: Google Cloud project setup

Before your app can upload videos to YouTube, you need a Google Cloud project with the YouTube Data API v3 enabled:

  1. Create a project in the Google Cloud Console and enable the YouTube Data API v3
  2. Configure the OAuth consent screen — Set up your app name, scopes, and authorized domains. Choose “External” user type if publishing on behalf of other YouTube accounts
  3. Create OAuth 2.0 credentials — Generate a client ID and client secret for your application type (web app, server-side, etc.)
  4. Submit for verification — Apps requesting sensitive scopes must pass Google’s OAuth verification process, which includes a security assessment and may require a third-party audit for restricted scopes

Unverified apps are limited to 100 users and display a warning screen during authorization. API projects created after July 28, 2020 that haven’t passed a compliance audit are restricted to uploading private videos only.

Required permissions

YouTube uses OAuth 2.0 scopes to control access. To upload videos and manage channel content, your app needs these scopes approved:

  • openid — Verify the user’s identity
  • email — Access the user’s email address
  • profile — Access basic profile information
  • https://www.googleapis.com/auth/youtube.upload — Upload videos
  • https://www.googleapis.com/auth/youtube — Manage the YouTube account (required for updating video metadata, setting thumbnails, and managing playlists)

All API requests require either an OAuth 2.0 access token or an API key. Upload operations always require OAuth.

Uploading a video

Videos are uploaded via a single videos.insert call that sends both metadata and the video file. The endpoint supports resumable uploads for large files or unreliable connections.

Simple upload

POST to https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&part=snippet,status:

The request body contains the video resource metadata:

{
"snippet": {
"title": "Your video title",
"description": "Video description text",
"tags": ["tag1", "tag2"],
"categoryId": "22"
},
"status": {
"privacyStatus": "public",
"selfDeclaredMadeForKids": false
}
}

Include the video file as the request body with the appropriate Content-Type header (video/* or application/octet-stream).

Maximum file size: 256 GB. Returns the full video resource including the assigned video ID on success.

Resumable upload

For large files, use the resumable upload protocol:

Step 1: Initiate the upload

POST to https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&part=snippet,status with the video metadata as the request body and these headers:

Authorization: Bearer {ACCESS_TOKEN}
Content-Type: application/json; charset=UTF-8
X-Upload-Content-Length: {FILE_SIZE_IN_BYTES}
X-Upload-Content-Type: video/*

Returns a 200 OK with a Location header containing the resumable upload URI.

Step 2: Upload the video file

PUT to the resumable upload URI from step 1 with the video binary data:

Content-Length: {FILE_SIZE_IN_BYTES}
Content-Type: video/*

For chunked uploads, send each chunk with a Content-Range header:

Content-Range: bytes {FIRST}-{LAST}/{TOTAL}

Step 3: Handle interruptions

If an upload is interrupted, send an empty PUT to the resumable URI with:

Content-Range: bytes */{TOTAL}

The response tells you which bytes were received, so you can resume from where you left off.

Video metadata fields

FieldRequiredDescription
snippet.titleYesVideo title, max 100 characters
snippet.descriptionNoVideo description, max 5,000 characters
snippet.tagsNoList of keyword tags
snippet.categoryIdYesNumeric video category ID
snippet.defaultLanguageNoLanguage of the video’s default metadata
status.privacyStatusYespublic, private, or unlisted
status.publishAtNoScheduled publish time (ISO 8601). Requires privacyStatus set to private
status.selfDeclaredMadeForKidsYesWhether the video is made for kids
status.containsSyntheticMediaNoWhether the video contains AI-generated content
status.embeddableNoWhether the video can be embedded on other sites
status.licenseNoyoutube (standard) or creativeCommon
recordingDetails.recordingDateNoDate the video was recorded (ISO 8601)

The notifySubscribers query parameter (default true) controls whether subscribers receive a notification about the upload.

Setting custom thumbnails

After uploading a video, set a custom thumbnail with thumbnails.set:

POST to https://www.googleapis.com/upload/youtube/v3/thumbnails/set?videoId={VIDEO_ID}:

Include the image as the request body. Accepted formats: JPEG, PNG, GIF, BMP. Recommended resolution: 1280x720 pixels. Maximum file size: 2 MB.

Quota cost: 50 units.

Checking processing status

After upload, YouTube processes the video (transcoding, generating thumbnails, etc.). Check status with videos.list:

GET https://www.googleapis.com/youtube/v3/videos?id={VIDEO_ID}&part=status,processingDetails

Key status fields:

  • status.uploadStatusuploaded, processed, rejected, deleted, or failed
  • processingDetails.processingStatusprocessing, succeeded, failed, or terminated

Only the video owner can access processingDetails. Processing time depends on file size, format, and resolution — typically a few minutes for short videos, longer for 4K or lengthy content.

Quota system

YouTube Data API v3 uses a quota system instead of simple rate limits. Each Google Cloud project gets 10,000 units per day by default — shared across all users of your app.

Quota costs per operation:

OperationCost
videos.insert (upload)100 units
videos.update50 units
videos.list1 unit
thumbnails.set50 units
Search requests100 units

With the default 10,000-unit daily quota, you can upload approximately 100 videos per day before hitting the limit. Additional quota requires submitting a quota extension request through the Google Cloud Console.

The same video, through Postproxy

Here’s how it’s done with Postproxy. One simple request with only what matters:

Terminal window
curl -X POST "https://api.postproxy.dev/api/posts" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"post": {
"body": "3 tips that changed how we approach customer onboarding"
},
"profiles": ["youtube"],
"media": ["https://example.com/video.mp4"]
}'

One request. Postproxy handles the resumable upload, metadata formatting, processing status polling, and thumbnail management.

What Postproxy handles

Postproxy maintains a verified Google Cloud project and handles the complexity:

  • OAuth verification and consent screen approval
  • OAuth 2.0 token exchange and refresh
  • Resumable video uploads with automatic retry on interruption
  • Video metadata formatting and category mapping
  • Processing status polling until the video is live
  • Quota monitoring and usage tracking
  • Privacy status and scheduling support

Your system sends content. Postproxy handles the YouTube-specific implementation.

Connect your YouTube channel and start publishing through the Postproxy API.

Ready to get started?

Start with our free plan and scale as your needs grow. No credit card required.