YouTube Data API v3: Upload a Video
The exact YouTube Data API v3 call to upload a video, and the metadata it requires.
Upload with videos.insert: an authenticated POST to https://www.googleapis.com/upload/youtube/v3/videos with at minimum part=snippet,status, a body carrying snippet.title, status.privacyStatus, and status.selfDeclaredMadeForKids, and the video bytes. Add uploadType=resumable for anything beyond a trivial clip. A successful response returns the created video resource with its id.
The exact call is videos.insert on the YouTube Data API v3 — an authenticated upload to https://www.googleapis.com/upload/youtube/v3/videos that combines a JSON description of the video with the video bytes themselves. Here is precisely what it takes: the endpoint, the required part parameters, the minimum request body, and what a successful response looks like.
The endpoint and required query parameters
POST /upload/youtube/v3/videos against the www.googleapis.com upload host, with an OAuth 2.0 bearer token scoped to the target channel. The part query parameter is required and tells the API which parts of the video resource your request body populates — at minimum snippet (title, description, category) and status (privacy, audience declaration). For anything larger than a trivial test clip, add uploadType=resumable — see YouTube Resumable Upload API for that protocol.
What is the minimum request body?
snippet.title is required. status.privacyStatus and status.selfDeclaredMadeForKids are both required in practice — YouTube rejects uploads that omit the audience declaration. Everything else (description, tags, category, scheduled release via publishAt) is optional but commonly set.
{
"snippet": {
"title": "Launch story",
"description": "How we shipped it.",
"categoryId": "28"
},
"status": {
"privacyStatus": "private",
"selfDeclaredMadeForKids": false
}
}What does a successful response look like?
A successful videos.insert returns the created video resource, including its id — the value you need for any follow-up call (updates, thumbnail sets, or later deletion). Processing is not necessarily finished when this response comes back; check status.uploadStatus for whether the video is still processed versus uploaded and awaiting YouTube's pipeline, per Google's videos.insert reference.
The equivalent call through PostGate
PostGate maps this same call to post.options.youtube on POST /api/posts, handling channel authorization, the resumable transfer, and the required metadata mapping so your integration only supplies title, privacy, and the audience declaration once — see YouTube Upload API for that request shape.
curl -X POST https://postgate.studio/api/posts \
-H "Authorization: Bearer $POSTGATE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"post": {
"body": "Launch day.",
"options": {
"youtube": {
"title": "Launch story",
"privacy": "private",
"made_for_kids": false,
"community_guidelines_confirmed": true
}
}
},
"profiles": ["pro_youtube123"],
"media": ["med_01JXYZ"]
}'What does this call cost?
Each videos.insert call draws from its own fixed daily allowance, separate from most other endpoints — see YouTube API Quota Cost per Upload for the exact accounting.
Frequently asked questions
Which fields are required to upload a YouTube video via API?
snippet.title is required, and status.privacyStatus and status.selfDeclaredMadeForKids are both required in practice — YouTube rejects uploads that omit the audience declaration. Everything else (description, tags, category, scheduled release via publishAt) is optional but commonly set.
Is the video ready when videos.insert returns?
Not necessarily. A successful videos.insert returns the created video resource including its id, but processing is not necessarily finished — check status.uploadStatus for whether the video is still processed versus uploaded and awaiting YouTube’s pipeline.
Do I need resumable upload for videos.insert?
For anything larger than a trivial test clip, yes — add uploadType=resumable so the file transfer becomes a session you can pause, resume, and query rather than a single request that restarts from zero on failure.
What quota does a videos.insert call consume?
Each videos.insert call draws from its own fixed daily allowance, separate from most other endpoints — not from the shared quota pool most other calls use.
