Cover for YouTube Upload API Without Google Cloud: 3 curl Calls

YouTube Upload API Without Google Cloud: 3 curl Calls

Upload videos to YouTube through an API in three curl calls, with no Google Cloud project, OAuth consent screen, app verification or quota audit.

Nov 1, 20269 min readAlexandroAlexandro
Table of Contents

You can upload a video to YouTube through an API in three calls, and you never create a Google Cloud project, configure an OAuth consent screen or wait for API approval. Connect your channel to PublishQ once in the browser, create an API key, then: list your accounts to get the YouTube account ID, upload the video file, and create a post with that account and that video. The video goes live on your channel, or at the time you schedule.

youtube data api setup google cloud project oauth verification

The rest of this page shows the exact curl commands, what Google asks of you if you build on the YouTube Data API yourself, and how to hand the whole thing to an AI agent.

What Google asks before your first upload

The YouTube Data API is the official way to upload, and it works well once it is set up. The setup is the slow part. Google's docs list it plainly:

  • Create or pick a project in the Google Cloud console, open the API Library and enable YouTube Data API v3.1
  • Create an OAuth 2.0 client ID, because uploading is a write operation and write operations need OAuth, not an API key.1
  • Configure the OAuth consent screen. Apps that request sensitive or restricted scopes go through Google's app verification, and Google's own example of a sensitive scope is deleting a YouTube video.2
  • Until verification is done, users see an "unverified app" screen and the app is capped at 100 new users. Google says verification can take several months, depending on how sensitive the data is.3
  • While the consent screen is in "Testing" for external users, refresh tokens expire after 7 days, so a cron job that uploads every week quietly breaks.4
  • Each project gets a default quota of 100 videos.insert calls a day, plus 10,000 units a day for everything else.5 An upload costs 1 unit in its own Video Uploads bucket.6
  • More quota than the default means completing an API compliance audit through YouTube's audit and quota extension form, then waiting for the YouTube API Services team to reply.7

None of this is hard for a team with a product, a privacy policy and a verified domain. For a solo creator, a small agency or a script that should just post the Monday video, it is a lot of paperwork before a single byte moves.

Build on the YouTube Data API yourself vs PublishQ's API

YouTube Data API, your own projectPublishQ API
Google Cloud projectYou create one and enable the API1Not needed
OAuth client and consent screenYou build and host the OAuth flow1You click Connect in PublishQ once
App verificationRequired for public apps using sensitive scopes2Not needed
Token handlingYour code stores and refreshes tokens; Testing-mode tokens expire in 7 days4One pq_live_ key in an Authorization header
Upload quotaDefault of 100 uploads a day per project, audit to raise it57No quota request and no audit on your side
Large filesResumable upload protocolSigned storage upload, files up to 4 GB
Other platformsA separate integration for each oneSame call, add TikTok, Instagram or Facebook accounts

If you are building your own YouTube product for thousands of users, Google's API is the right tool and the table above is the price of entry. If you want a video on your channel from code today, keep reading.

Before you start

Sign up at PublishQ, connect your YouTube channel from the dashboard, and create a key at https://publishq.com/app/api-keys. Put it in your shell:

export PQ_KEY="pq_live_..."

The API is on every plan, the Free plan included. The full YouTube reference lives at the YouTube API docs.

Step 1: get your YouTube account ID

Ask for your connected accounts and filter to YouTube:

curl -s "https://publishq.com/api/v1/accounts?platform=YOUTUBE" \
  -H "Authorization: Bearer $PQ_KEY"

You get back an accounts array. Each entry has the PublishQ id you will post to, plus the channel name and handle so you can tell channels apart:

{
  "accounts": [
    {
      "id": "f0e1d2c3-b4a5-6789-0123-456789abcdef",
      "platform": "YOUTUBE",
      "platformName": "My Channel",
      "platformUsername": "@mychannel"
    }
  ]
}

Copy the id. It does not change, so you can store it in your script's config.

Step 2: upload the video

For a file up to 100 MB, one multipart request does it:

curl -s -X POST https://publishq.com/api/v1/media \
  -H "Authorization: Bearer $PQ_KEY" \
  -F "[email protected]"

A long video passes 100 MB fast, so here is the storage upload, which takes files up to 4 GB. First tell PublishQ the name, type and exact size in bytes:

curl -s -X POST https://publishq.com/api/v1/media/uploads \
  -H "Authorization: Bearer $PQ_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"filename\":\"launch-video.mp4\",\"contentType\":\"video/mp4\",\"fileSize\":$(wc -c < launch-video.mp4)}"

The response holds the media id and a signed uploadUrl. PUT the file straight to that URL. It goes to storage, not to the PublishQ API, so it carries no Authorization header:

curl -X PUT "$UPLOAD_URL" \
  -H "Content-Type: video/mp4" \
  --upload-file launch-video.mp4

Storage answers 200 with an empty body. The uploadUrl is good for 1 hour. There is an optional complete call that adds the file to your media library right away, but you can skip it: using the id in a post does the same. The media uploads guide covers folders and the error codes.

upload video to youtube with curl api calls

Step 3: create the post

The post's content is the YouTube title, up to 100 characters. Everything YouTube-specific goes in platformSpecificSettings:

curl -s -X POST https://publishq.com/api/v1/posts \
  -H "Authorization: Bearer $PQ_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "I rebuilt my publishing pipeline in a weekend",
    "mediaIds": ["e1d2c3b4-a5f6-4789-9012-3456789abcde"],
    "accounts": [{
      "accountId": "f0e1d2c3-b4a5-6789-0123-456789abcdef",
      "platformSpecificSettings": {
        "description": "Write-up and config files are linked below.",
        "privacyStatus": "unlisted",
        "categoryId": "28",
        "tags": ["automation", "publishing"],
        "madeForKids": false
      }
    }],
    "publishNow": true
  }'

That is the whole upload. A few details worth knowing:

  • Swap "publishNow": true for "scheduledAt": "2026-12-01T09:00:00Z" to schedule it. Leave both out and the post waits in PublishQ as a draft.
  • privacyStatus is public when you leave it out. The description takes up to 5000 characters and tags up to 500 characters in total.
  • A title over 100 characters is refused with an error, not cut short, so you find out before anything goes live.
  • For a custom thumbnail, upload a JPEG or PNG the same way and pass its ID as thumbnailMediaId. YouTube only accepts custom thumbnails on verified channels. If yours is not, the video still publishes and PublishQ tells you why the thumbnail was refused.
  • A vertical 9:16 video of 3 minutes or less becomes a Short on its own. There is no flag to set. The Shorts safe zone checker shows where YouTube's buttons will cover your frame.

Every field is listed in the create posts reference, and the YouTube limits page has the file and length limits YouTube enforces.

The same three steps without curl

In Node, the SDK picks the right upload method for the file size, so the upload is one line: await publishq.media.upload({ file }). From a terminal or a CI job, the CLI does the same with pq media upload --file ./launch-video.mp4, then pq posts create --content "Title" --account <id> --media-id <id>. Both return JSON.

Let an agent make the calls

If you would rather describe the upload than write it, Claude Code, Cursor and Codex can run these steps for you through PublishQ's MCP server. In Claude Code:

claude mcp add --transport http publishq https://publishq.com/mcp

Then run /mcp, pick Authenticate and approve the login in your browser. Ask for "upload ./launch-video.mp4 to my YouTube channel as unlisted, title it X" and the agent calls publishq_list_accounts, publishq_upload_media and publishq_create_post, the same three steps. The YouTube MCP walkthrough for Claude Code goes further.

Setup guides for other agents:

For any other agent, open https://publishq.com/agents and paste the line at the top of that page into your agent. It sets itself up and sends you a link to approve the login in your browser.

youtube video published through api

Start uploading

The Google Cloud route is still there if you need it. If what you need is a video on your channel from a script or an agent this afternoon, skip the console: create a PublishQ account, connect your channel and run the three calls above. More on the endpoints is on the YouTube API page.

Footnotes

  1. Obtaining authorization credentials - YouTube Data API (2026-11) - project creation, enabling YouTube Data API v3, OAuth 2.0 client ID required for write requests ↩ ↩2 ↩3 ↩4

  2. App verification to use Google Authorization APIs (2026-11) - apps requesting sensitive or restricted scopes need verification; deleting a YouTube video given as an example of a sensitive scope ↩ ↩2

  3. Unverified apps - Google Cloud Platform Console Help (2026-11) - unverified app screen, 100 new user cap, verification can take several months ↩

  4. Using OAuth 2.0 to Access Google APIs (2026-11) - refresh tokens expire in 7 days for external apps in Testing status ↩ ↩2

  5. YouTube Data API Overview (2026-11) - default quota of 100 videos.insert calls and 10,000 units per day ↩ ↩2

  6. Videos: insert - YouTube Data API (2026-11) - upload costs 1 unit in the Video Uploads quota bucket, 100 calls per day ↩

  7. Quota and Compliance Audits - YouTube Data API (2026-11) - audit required before requesting quota beyond the default, via the Audit and Quota Extension Form ↩ ↩2

Frequently Asked Questions

Direct answers extracted from this article.

Yes. Google's YouTube Data API has a videos.insert method, but it needs a Google Cloud project, an OAuth client and consent screen, and an audit for more than the default quota. With PublishQ you connect your channel once and upload with three calls: list accounts, upload the video, create the post.
Yes. Connect your YouTube channel in PublishQ, create a pq_live_ API key, and call the PublishQ API. PublishQ handles the connection to YouTube, so you never open the Google Cloud console or request API access.
Use PublishQ's storage upload. POST /media/uploads with the file name, type and exact size returns a signed uploadUrl. PUT the file to that URL, then use the returned media ID in POST /posts. Files up to 4 GB are accepted.
Yes. Send scheduledAt with an ISO date instead of publishNow: true when you create the post. Scheduled posts can be edited or cancelled until they go out. Leave both out to save the post as a draft.
Yes. Add the PublishQ MCP server with claude mcp add --transport http publishq https://publishq.com/mcp, authenticate in your browser, and ask Claude Code to upload a file. Cursor and Codex work the same way.
Start for Free

No credit card required • Set up in under 3 minutes