The YouTube Data API uploads videos through videos.insert, and two documented facts decide whether it is viable for your product. Videos uploaded from unverified API projects created after 28 July 2020 are restricted to private mode until the project passes an audit. And videos.insert draws on its own quota bucket of 100 calls per day, separate from the 10,000-unit pool the rest of the API shares.
Read those together and the picture is clear: without an audit you cannot publish publicly, and without a quota increase you cannot publish often.
What can the YouTube Data API publish, and what is the audit gate?
videos.insert uploads a video file and sets its metadata: title, description, tags, category, and a privacyStatus of public, private or unlisted. The documented maximum file size is 256GB, and accepted MIME types are video/* and application/octet-stream.
The gate is the audit. Google’s documentation states that videos uploaded from unverified API projects created after 28 July 2020 are restricted to private mode until the project undergoes an audit. In practice that means your integration works end to end during development, produces a real video ID, and the video is invisible to everyone but the channel owner. Passing the audit is what lifts the restriction so privacyStatus: 'public' is honoured.
Note: Figures here were verified against developers.google.com/youtube as of September 2026. Platforms change these without notice.
| Question | Answer from the docs |
|---|---|
| Upload endpoint | POST https://www.googleapis.com/upload/youtube/v3/videos |
| Scopes | youtube.upload, youtube, youtubepartner or youtube.force-ssl |
| Max file size | 256GB |
| MIME types | video/*, application/octet-stream |
| Privacy values | public, private, unlisted |
| Unverified projects | Uploads restricted to private until the project is audited |
What is the auth model, and how long does the audit take?
Standard OAuth 2.0 with offline access. You redirect the channel owner to Google’s consent screen requesting https://www.googleapis.com/auth/youtube.upload, exchange the code for an access token and a refresh token, and refresh the access token as it expires.
Because the upload scope is a sensitive scope, your project also goes through Google’s OAuth verification in addition to the YouTube API audit. These are two separate reviews and people routinely confuse them: OAuth verification governs the consent screen and how many users can grant it, the YouTube audit governs whether your uploads can be anything other than private.
We could not find a published turnaround duration for the YouTube API audit in the official documentation, so we are not going to state one. Assume it is measured in weeks, not days, and start it before you need it.
What is the actual upload sequence?
Uploads are resumable: you open an upload session, then send the bytes to the session URI. The video then processes asynchronously on YouTube’s side after your request completes.
- Open a resumable session.
POSTto the upload endpoint with the video metadata as JSON anduploadType=resumable. The response returns a session URI in theLocationheader. Note thatuploadType=resumableand theLocationsession URI are Google’s general resumable-upload mechanics rather than something the YouTube-specific upload page documents, which only shows the Python client library. - PUT the bytes to that session URI, in one request or in chunks. Chunking lets you resume after a network failure instead of restarting a large file.
- Read the video ID from the final response. The upload is now complete.
- Poll for processing. YouTube transcodes asynchronously. The video ID exists before the video is watchable, and processing can fail after a successful upload.
# 1. open the resumable session
curl -X POST \
"https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&part=snippet,status" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-H "X-Upload-Content-Type: video/mp4" \
-d '{"snippet":{"title":"Release notes","categoryId":"28"},
"status":{"privacyStatus":"private"}}' -D -
# 2. PUT the bytes to the Location URI returned above
curl -X PUT "$SESSION_URI" \
-H "Content-Type: video/mp4" --data-binary @video.mp4
# 3. then poll videos.list for processing status using the returned video id
Google’s own upload guide is a Python sample built around MediaFileUpload with resumable=True and exponential backoff on retries, and it states plainly that the sample script does no error handling. Take that at face value: the sample is a starting point, not a template for production.
Note: Figures here were verified against developers.google.com/youtube as of September 2026. Platforms change these without notice.
What does an upload cost in quota?
This is the number that ends most YouTube integration plans, and it is worth stating precisely.
| Method | Quota cost |
|---|---|
videos.insert | 1 unit, against a dedicated 100-calls-per-day bucket |
videos.list | 1 unit |
thumbnails.set | 50 units |
videos.update | 50 units |
The default allocation, in Google’s wording, is “100 search.list calls, 100 videos.insert calls, and 10,000 units per day combined for all other endpoints.”
The binding constraint on publishing is therefore a count, not unit arithmetic: 100 uploads per project per day. The 10,000-unit pool is separate and has to cover every status poll, metadata read and thumbnail set around those uploads, which is generous by comparison. Quota resets at midnight Pacific time. A multi-tenant product serving more than a handful of channels needs a quota increase request, which is its own application to Google.
Older guides (and some still-live ones) state that videos.insert costs 1,600 units against the shared 10,000-unit pool, which worked out to six uploads a day. That is no longer what Google’s quota documentation says, and it is worth checking any budget you built on it.
Note: Figures here were verified against developers.google.com/youtube as of September 2026. Platforms change these without notice.
What will actually cost you three weeks
- Two reviews, not one. OAuth verification for the sensitive upload scope, and the YouTube API audit that lifts the private-upload restriction. Neither publishes a turnaround. Both block launch.
- Quota, and the request to raise it. 100 uploads per project per day is not a production budget once you are publishing for more than a few dozen channels. The increase request is a form, a justification and a wait.
- Transcoding before you even reach Google. Accepting arbitrary user video means normalising container and codec, generating a thumbnail, and holding the file somewhere you can stream 256GB from without buffering it in memory.
- Async failure after a successful upload. This is the one that surprises people. A 200 and a video ID means the bytes landed, not that the video is live. Processing can fail afterwards, and a rejected upload surfaces as a processing status, not as an HTTP error. You need a poller, a
processingpost state, and a way to tell a user their video failed an hour after your API call succeeded.
If you also plan to push the same vertical video to other networks, the shape of that work is covered in cross-posting Instagram Reels to YouTube Shorts and posting to TikTok, Reels and Shorts at once. Each of those platforms has its own audit, its own quota model and its own async failure mode, which is the point.
The short version
videos.insertuploads tohttps://www.googleapis.com/upload/youtube/v3/videos, max 256GB, scopeyoutube.upload.- Unverified projects created after 28 July 2020 can only upload private videos until the project is audited.
- The flow is: open a resumable session, PUT the bytes, then poll, because processing is asynchronous and can fail after the upload succeeds.
videos.insertcosts 1 unit against a dedicated bucket of 100 calls per day. A separate 10,000 units per day covers everything else.- No audit turnaround duration is published. Start the review before you need it.
Doing this once instead of once per platform
The YouTube work above is real, and none of it transfers to the next platform. Pinterest has a different review, TikTok has its own Content Posting API audit, and each has a separate media pipeline. That repetition is what our API removes: BulkPublish publishes to 15 platforms through one REST endpoint, with OAuth, token refresh, media handling and asynchronous status tracking handled on our side. Post states include processing and partial precisely because a 200 is not a publish.
The developer docs list the endpoints, and the REST API integration page covers authentication and the post lifecycle. If you only need scheduling rather than an integration, how to schedule YouTube videos covers that, and the free YouTube character counter checks titles and descriptions against the limits.