Posts

Upload videos to YouTube through the shared posts API, with visibility settings, Shorts, and scheduling.

Publishing to a YouTube channel means uploading exactly one video through the shared posts surface with mediaKind: "video". Any other kind is rejected.

Quick Start

Upload a video in under a minute:

import { Configuration, PostsApi } from "@onepostly/sdk";

const postsApi = new PostsApi(
  new Configuration({ apiKey: process.env.ONEPOSTLY_API_KEY })
);

const response = await postsApi.createPost({
  createPostBody: {
    "text": "My first upload",
    "mediaUrls": [
      "https://cdn.onepostly.com/media/demo.mp4"
    ],
    "mediaKind": "video",
    "destinations": [
      {
        "accountId": "a1b2c3d4-e5f6-4a7b-8c9d-e0f1a2b3c4d5"
      }
    ]
  },
});
console.log(response);
{
  "post": {
    "id": "b3e1a7c2-8f4d-4e6a-9c1b-2d3e4f5a6b7c",
    "text": "My first upload",
    "mediaUrls": [
      "https://cdn.onepostly.com/media/demo.mp4"
    ],
    "mediaKind": "video",
    "status": "queued",
    "scheduledFor": null,
    "timezone": null,
    "destinations": [
      {
        "id": "d4e5f6a7-8b9c-4d0e-8f1a-2b3c4d5e6f7a",
        "accountId": "a1b2c3d4-e5f6-4a7b-8c9d-e0f1a2b3c4d5",
        "platform": "youtube",
        "status": "draft",
        "externalPostId": "17895695668004550",
        "externalUrl": "https://www.youtube.com/watch?v=17895695668004550",
        "errorCode": null,
        "errorMessage": null,
        "publishedAt": "2026-08-25T10:00:00.000Z",
        "metrics": null
      }
    ],
    "createdAt": "2026-08-25T10:00:00.000Z",
    "updatedAt": "2026-08-25T10:00:00.000Z"
  }
}

The response is 202 Accepted with status: "queued". When published, the destination carries the YouTube video id (externalPostId) and a https://www.youtube.com/watch?v=VIDEO_ID link. Poll GET /v1/posts/:id until the destination is published or failed, or receive webhooks instead of polling.

Content Types

Regular Video

Long-form, horizontal (16:9) content. Upload exactly one video and YouTube handles the rest:

import { Configuration, PostsApi } from "@onepostly/sdk";

const postsApi = new PostsApi(
  new Configuration({ apiKey: process.env.ONEPOSTLY_API_KEY })
);

const response = await postsApi.createPost({
  createPostBody: {
    "text": "Build a REST API from Scratch",
    "mediaUrls": [
      "https://cdn.onepostly.com/media/rest-api-tutorial.mp4"
    ],
    "mediaKind": "video",
    "destinations": [
      {
        "accountId": "YOUR_YOUTUBE_ACCOUNT_ID",
        "privacyStatus": "public",
        "description": "In this tutorial, I walk through building a REST API from scratch.\n\nTimestamps and links in the description."
      }
    ]
  },
});
console.log(response);
{
  "post": {
    "id": "b3e1a7c2-8f4d-4e6a-9c1b-2d3e4f5a6b7c",
    "text": "Build a REST API from Scratch",
    "mediaUrls": [
      "https://cdn.onepostly.com/media/rest-api-tutorial.mp4"
    ],
    "mediaKind": "video",
    "status": "queued",
    "scheduledFor": null,
    "timezone": null,
    "destinations": [
      {
        "id": "d4e5f6a7-8b9c-4d0e-8f1a-2b3c4d5e6f7a",
        "accountId": "YOUR_YOUTUBE_ACCOUNT_ID",
        "platform": "youtube",
        "status": "draft",
        "externalPostId": "17895695668004550",
        "externalUrl": "https://www.youtube.com/watch?v=17895695668004550",
        "errorCode": null,
        "errorMessage": null,
        "publishedAt": "2026-08-25T10:00:00.000Z",
        "metrics": null
      }
    ],
    "createdAt": "2026-08-25T10:00:00.000Z",
    "updatedAt": "2026-08-25T10:00:00.000Z"
  }
}

Shorts

There is no separate Shorts post type. YouTube classifies a video as a Short when it is vertical (9:16) and 3 minutes or shorter. Anything else is a regular video. No flag is needed.

  • The upload flow is identical to regular videos
  • Shorts do not support custom thumbnails
  • Videos under 15 seconds loop automatically on YouTube

Destination Parameters

Every YouTube destination accepts the following parameters.

Prop

Type

text maps to the YouTube title, truncated at 100 characters. A title override wins when both are present. All fields above are YouTube-only. Sending them on a non-YouTube destination returns VALIDATION_ERROR.

Title And Description Formatting

Both are plain text. Markdown or HTML tags appear as literal characters on YouTube. Newlines work: use "Line one\nLine two" in JSON.

Media Requirements

PropertyRequirement
Videos per postExactly 1
Onepostly upload cap256 MB
YouTube native limit256 GB
FormatsMP4, MOV, AVI, WMV, FLV, 3GP, WebM
RecommendedMP4 (H.264 video, AAC audio)
Regular videos16:9 horizontal, 1080p or higher
Shorts9:16 vertical, 1080 × 1920, 3 minutes or shorter

Media URL Requirements

These do not work as media URLs:

  • Google Drive returns an HTML download page, not the file
  • Dropbox returns an HTML preview page
  • OneDrive / SharePoint returns HTML
  • iCloud returns HTML

Test your URL in an incognito browser window. If you see a webpage instead of the raw video, the URL will not work.

Any public HTTPS URL that returns video bytes works. Host media on a fast, reliable CDN.

Processing takes time

Large videos can take 30 to 60 minutes to process on YouTube's side after the upload completes. The destination is already published at that point. Do not re-upload while YouTube is still processing.

Schedule

Add scheduledFor (local wall time) and timezone to the same call. The request shape is otherwise identical to an immediate upload.

  • timezone defaults to UTC. Use an IANA name like Europe/Istanbul
  • Do not append Z or an offset to scheduledFor. It is local wall time
  • Scheduled posts return 201 Created and upload automatically at the scheduled moment
  • Max 1 year ahead
  • Cancel with posts.cancelPost({ id }) / posts.cancel_post(id=…), or DELETE /v1/posts/:id, any time before then

Limits

LimitValue
Onepostly upload cap256 MB
Google quota per upload1,600 units (~6 uploads/day on default quota)
Title length100 characters (longer input is truncated)
Description length5,000 characters (over-length returns VALIDATION_ERROR)

If an upload fails right after you published several videos, you have likely hit the daily quota. Retry the next day.

Remote Delete

Removes the video from the channel and emits the post.platform.deleted webhook:

import { Configuration, PostsApi } from "@onepostly/sdk";

const postsApi = new PostsApi(
  new Configuration({ apiKey: process.env.ONEPOSTLY_API_KEY })
);

const response = await postsApi.deletePostDestination({
  destinationId: "d4e5f6a7-8b9c-4d0e-8f1a-2b3c4d5e6f7a",
});
console.log(response);
{
  "post": {
    "id": "b3e1a7c2-8f4d-4e6a-9c1b-2d3e4f5a6b7c",
    "text": "My first upload",
    "mediaUrls": [
      "https://cdn.onepostly.com/media/demo.mp4"
    ],
    "mediaKind": "video",
    "status": "queued",
    "scheduledFor": null,
    "timezone": null,
    "destinations": [
      {
        "id": "d4e5f6a7-8b9c-4d0e-8f1a-2b3c4d5e6f7a",
        "accountId": "a1b2c3d4-e5f6-4a7b-8c9d-e0f1a2b3c4d5",
        "platform": "youtube",
        "status": "queued",
        "externalPostId": "dQw4w9WgXcQ",
        "externalUrl": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
        "errorCode": null,
        "errorMessage": null,
        "publishedAt": null
      }
    ],
    "createdAt": "2026-08-25T10:00:00.000Z",
    "updatedAt": "2026-08-25T10:00:00.000Z"
  }
}

Publish Errors

CodeCauseFix
UNSUPPORTED_MEDIA_KINDmediaKind other than videoYouTube only accepts video
INVALID_MEDIAMore than one media URL, or a non-video filePass exactly one video URL
MEDIA_UNFETCHABLEThe video URL could not be downloadedUse a public HTTPS URL
MEDIA_UPLOAD_FAILEDUpload rejected by YouTubeCheck size (256 MB cap), format (MP4), and retry
UPLOAD_LIMIT_EXCEEDEDThe channel has used YouTube's daily video upload allowancePost the remaining videos after the allowance resets
QUOTA_EXCEEDEDYouTube's own API quota for the day is spentPost again once the quota resets
RATE_LIMITEDYouTube throttled the requestWait out the window, then post again
PERMISSION_DENIED403 from YouTube. Suspended channel or missing scopesCheck the error message, then reconnect the account
UNSUPPORTED_FEATUREquoteTweetId or reply fields sent to YouTubeThese are not YouTube concepts. Remove them
TOKEN_INVALIDConnection token expired or revokedReconnect the account
VALIDATION_ERROROver-length description, or a YouTube-only field on another platformTrim the description

See Also