From a8e283f088ff5ac75697d40b91b634e54cbb231f Mon Sep 17 00:00:00 2001 From: Paulo Castellano Date: Fri, 11 Sep 2026 22:09:48 -0300 Subject: [PATCH 1/5] docs: media limits catalog per content type with official specs Expand knowledge-base/media.mdx Buffer-style: Cloud size catalog, per-content_type size / duration / format with the official API page, what TryPost does to images vs video as-is, and FAQs (900 MB Instagram, feed video publishes as Reel, Telegram URL 5/20, Bluesky MP4 only). Each platform page gets a short table and a pointer back to Media. Document the new accepts_mov flag on GET /content-types and the MCP tool. --- ai/tools-reference.mdx | 2 +- api-reference/endpoint/list-content-types.mdx | 2 + knowledge-base/media.mdx | 205 +++++++++++++----- platforms/bluesky.mdx | 8 + platforms/discord.mdx | 8 + platforms/facebook.mdx | 10 + platforms/instagram.mdx | 10 + platforms/linkedin.mdx | 8 + platforms/mastodon.mdx | 8 + platforms/pinterest.mdx | 10 + platforms/telegram.mdx | 8 + platforms/threads.mdx | 8 + platforms/tiktok.mdx | 9 + platforms/x-twitter.mdx | 8 + platforms/youtube.mdx | 8 + 15 files changed, 255 insertions(+), 57 deletions(-) diff --git a/ai/tools-reference.mdx b/ai/tools-reference.mdx index 4ed547d..e2e79b3 100644 --- a/ai/tools-reference.mdx +++ b/ai/tools-reference.mdx @@ -102,7 +102,7 @@ Attach a library file to a post. Does **not** upload a new file. REST: [`POST /p | Tool | Description | |------|-------------| -| **list-content-types-tool** | Returns `{ platforms: [...] }` — same catalog as [`GET /content-types`](/api-reference/endpoint/list-content-types). Each platform has `max_content_length`, `recommended_content_length`, `allowed_media_types`, `default_content_type`, and `content_types[]` rows with `max_media_count`, `min_media_count`, `requires_media`, `accept_images` / `accept_videos` / `accept_documents` / `accepts_gif`, `forbids_mixed_media`, and per-type byte caps. **20** content types total — there is no `linkedin_carousel` / `instagram_carousel`. Use before `create-post-tool` / `update-post-tool`. | +| **list-content-types-tool** | Returns `{ platforms: [...] }` — same catalog as [`GET /content-types`](/api-reference/endpoint/list-content-types). Each platform has `max_content_length`, `recommended_content_length`, `allowed_media_types`, `default_content_type`, and `content_types[]` rows with `max_media_count`, `min_media_count`, `requires_media`, `accept_images` / `accept_videos` / `accept_documents` / `accepts_gif` / `accepts_mov`, `forbids_mixed_media`, and per-type byte caps. **20** content types total — there is no `linkedin_carousel` / `instagram_carousel`. Use before `create-post-tool` / `update-post-tool`. | ## Signatures diff --git a/api-reference/endpoint/list-content-types.mdx b/api-reference/endpoint/list-content-types.mdx index bc72a05..ffb5d50 100644 --- a/api-reference/endpoint/list-content-types.mdx +++ b/api-reference/endpoint/list-content-types.mdx @@ -40,6 +40,7 @@ Returns `{ "platforms": [ ... ] }` — one object per social platform. | `accept_videos` | Whether videos are allowed. | | `accept_documents` | Whether PDFs are allowed (e.g. LinkedIn document posts). | | `accepts_gif` | Whether GIF is accepted as an image. | +| `accepts_mov` | Whether QuickTime/MOV is accepted. `false` on Bluesky (MP4 only). | | `forbids_mixed_media` | When `true`, do not mix images and videos in one post. | | `max_video_duration_sec` | Max video length in seconds, or `null`. | | `max_image_bytes` | Max image size in bytes, or `null`. | @@ -91,6 +92,7 @@ Returns `{ "platforms": [ ... ] }` — one object per social platform. "accept_videos": true, "accept_documents": true, "accepts_gif": false, + "accepts_mov": true, "forbids_mixed_media": true, "max_video_duration_sec": 600, "max_image_bytes": 5242880, diff --git a/knowledge-base/media.mdx b/knowledge-base/media.mdx index b5fd1b2..5900c72 100644 --- a/knowledge-base/media.mdx +++ b/knowledge-base/media.mdx @@ -23,102 +23,183 @@ WebM is intentionally excluded — every major social platform rejects it, so ac ## Upload limits -| Type | Default cap | Override (self-hosted) | -|------|-------------|-----------------------| +These are the **Cloud** upload hard caps. Every path (dashboard, REST, MCP signed URL) uses the same per-type ceiling. A network that officially allows more is still clamped here. + +| Type | Cloud cap | Override (self-hosted) | +|------|-----------|------------------------| | Image | 10 MB per file | `MEDIA_IMAGE_MAX_SIZE_MB` | | Video | 1 GB per file | `MEDIA_VIDEO_MAX_SIZE_MB` | | Document (PDF) | 100 MB per file | `MEDIA_DOCUMENT_MAX_SIZE_MB` | -All upload paths (dashboard, REST, MCP signed URL) use the **same** per-type caps. There is no separate MCP-only size limit. +The editor, REST API, and MCP then apply a **tighter per-`content_type` cap** when the network's API is smaller than that hard cap. [`GET /content-types`](/api-reference/endpoint/list-content-types) is the live catalog — do not hard-code a second table of numbers. Files over 1 MB are sent in chunks (the dashboard streams them via `Content-Range` to the chunked upload endpoint) so big videos transfer reliably even on flaky connections. On self-hosted instances, raising the video cap also requires bumping PHP's `upload_max_filesize` / `post_max_size` and any reverse-proxy body-size cap to match. Signed upload URLs are single-use and expire after **15 minutes** by default (`MEDIA_SIGNED_UPLOAD_URL_TTL_MINUTES`; legacy fallback `MCP_UPLOAD_URL_TTL_MINUTES`). -## Platform content types and media requirements +## What TryPost does to your files + +**Images — we convert and, on most networks, resize.** + +- On store: PNG and WebP become JPEG. JPEG and GIF stay as they are. +- On publish, Instagram feed / carousel images are cropped to the feed window; Instagram Stories are fit onto a 9:16 canvas; Facebook feed images are cropped. +- On publish, stills sent to X, LinkedIn, Pinterest, Mastodon, Bluesky, Discord (not GIF), and TikTok photos are resized into that network's image budget and written as JPEG. +- Threads and Telegram receive the **original URL** — no crop and no optimize pass. + +**Videos — we do not transcode.** Upload accepts MP4 and MOV. What you attach is what the network receives (after the size / duration checks below). There is no FFmpeg step. + +**GIF:** only X, Bluesky, Mastodon, Discord, and Telegram accept an animated GIF. The editor blocks GIF on every other `content_type`. + +**MOV:** accepted everywhere except Bluesky. Bluesky's video lexicon is **MP4 only** — the editor and API reject MOV on `bluesky_post`. -Each platform supports different content formats with specific media requirements. Use [`GET /content-types`](/api-reference/endpoint/list-content-types) for the live, machine-readable version — that catalog is the source of truth. +## Size catalog (Cloud) + +Numbers below are what the editor and [`GET /content-types`](/api-reference/endpoint/list-content-types) enforce after the Cloud hard cap (10 MB image / 1 GB video). A dash means that media kind is not accepted for the type. + +| `content_type` | Image | Video | Max duration | +|----------------|-------|-------|--------------| +| `instagram_feed` | 8 MB | 100 MB | 60 seconds | +| `instagram_reel` | — | 300 MB | 15 minutes | +| `instagram_story` | 8 MB | 100 MB | 60 seconds | +| `facebook_post` | 4 MB | 1 GB | 240 minutes | +| `facebook_reel` | — | 1 GB | 90 seconds | +| `facebook_story` | — | 1 GB | 60 seconds | +| `linkedin_post` / `linkedin_page_post` | 5 MB | 1 GB | 10 minutes | +| `youtube_short` | — | 1 GB | 3 minutes | +| `pinterest_pin` | 10 MB | — | — | +| `pinterest_video_pin` | — | 1 GB | 15 minutes | +| `pinterest_carousel` | 10 MB | — | — | +| `x_post` | 5 MB | 1 GB | 20 minutes | +| `threads_post` | 8 MB | 1 GB | 5 minutes | +| `bluesky_post` | 2 MB | 300 MB | 60 seconds | +| `mastodon_post` | 10 MB | 40 MB | — | +| `tiktok_video` | — | 1 GB | per creator (`creator_info`) | +| `tiktok_photo` | 10 MB | — | — | +| `discord_message` | 10 MB | 20 MB | — | +| `telegram_post` | 5 MB | 20 MB | — | + +LinkedIn PDF posts: **100 MB**. TikTok video duration is not a fixed editor cap — TikTok returns it per creator. There is **no** `linkedin_carousel`, `linkedin_page_carousel`, or `instagram_carousel` content type on posts. Multi-image Instagram posts use `instagram_feed`. LinkedIn multi-image / PDF posts use `linkedin_post` / `linkedin_page_post` (format is inferred from the attached media; optional `meta.document_title` for PDFs). -### LinkedIn / LinkedIn Page +## Limits by content type -| Content type | Media | Max files | Notes | -|-------------|-------|-----------|-------| -| `linkedin_post` / `linkedin_page_post` | Optional | Up to 10 images, or 1 video, or 1 PDF | Images/videos/documents cannot be mixed. PDF posts can set `meta.document_title`. | +Each block is the TryPost-enforced cap plus the official spec page we follow. Aspect windows are the editor cropper bounds. -### X (Twitter) +### Instagram + +Official: [IG User Media — Image, Reel, Story specs](https://developers.facebook.com/docs/instagram-platform/instagram-graph-api/reference/ig-user/media/). -| Content type | Media | Max files | Notes | -|-------------|-------|-----------|-------| -| `x_post` | Optional | 4 images or 1 video | Images and video cannot be mixed | +| Type | Size | Duration | Format | Aspect | +|------|------|----------|--------|--------| +| `instagram_feed` | Image 8 MB; video 100 MB | 60 seconds | JPEG after store (PNG/WebP converted). GIF no. Video MP4 or MOV | 4:5 (0.80–1.91) | +| `instagram_reel` | Video 300 MB | 15 minutes | MOV or MP4 | 9:16 (0.50–0.60) | +| `instagram_story` | Image 8 MB; video 100 MB | 60 seconds | Same as feed. Stories auto-fit stills onto 9:16 | 9:16 (0.50–0.60) | + +A **single video** attached to `instagram_feed` publishes as a Reel. Use `instagram_reel` for anything longer than 60 seconds or larger than 100 MB (up to 300 MB / 15 minutes). Feed video is the carousel `media_type=VIDEO` path, not the Reel container. ### Facebook -| Content type | Media | Max files | Aspect | Notes | -|-------------|-------|-----------|--------|-------| -| `facebook_post` | Optional | Up to 10 images or 1 video | — | Standard page post | -| `facebook_reel` | Required | 1 video | 9:16 | Short-form vertical video | -| `facebook_story` | Required | 1 video | 9:16 | Vertical video story (up to 60s) | +Official: [Reels Publishing API](https://developers.facebook.com/docs/video-api/guides/reels-publishing/), [Page Stories API](https://developers.facebook.com/docs/page-stories-api/), [Video API error codes](https://developers.facebook.com/docs/video-api/reference/error-codes/). + +| Type | Size | Duration | Format | Aspect | +|------|------|----------|--------|--------| +| `facebook_post` | Image 4 MB; video 1 GB | 240 minutes | Feed photos cropped to JPEG. Video MP4 or MOV | — | +| `facebook_reel` | Video 1 GB | 90 seconds | MP4 recommended | 9:16 (0.50–0.60) | +| `facebook_story` | Video 1 GB | 60 seconds | MP4 recommended | 9:16 (0.50–0.60) | + +### Threads + +Official: [Overview — Image / Video Specifications](https://developers.facebook.com/docs/threads/overview/) and [Threads Posts](https://developers.facebook.com/docs/threads/posts/). + +| Type | Size | Duration | Format | +|------|------|----------|--------| +| `threads_post` | Image 8 MB; video 1 GB | 5 minutes | JPEG/PNG; video MOV or MP4. No crop — original URL | + +### X (Twitter) + +Official: [Media best practices](https://docs.x.com/x-api/media/quickstart/best-practices). + +| Type | Size | Duration | Format | +|------|------|----------|--------| +| `x_post` | Image 5 MB; video 1 GB | 20 minutes | JPG/PNG/GIF/WebP; video H.264 (MP4 or MOV). Stills become JPEG on publish; GIF stays GIF | -### Instagram (and Instagram via Facebook) +These are **Post** (`tweet_video`) limits, not Direct Message (`dm_video`) limits. -| Content type | Media | Max files | Aspect | Notes | -|-------------|-------|-----------|--------|-------| -| `instagram_feed` | Required | Up to 10 images, or 1 video | 4:5 | Single- or multi-image feed post (carousel = multiple images here) | -| `instagram_reel` | Required | 1 video | 9:16 | Short-form vertical video | -| `instagram_story` | Required | 1 image or 1 video | 9:16 | Disappears after 24 hours | +### LinkedIn + +Official: [Videos API](https://learn.microsoft.com/en-us/linkedin/marketing/community-management/shares/videos-api), [Images API](https://learn.microsoft.com/en-us/linkedin/marketing/community-management/shares/images-api), [Documents API](https://learn.microsoft.com/en-us/linkedin/marketing/community-management/shares/documents-api). + +| Type | Size | Duration | Format | +|------|------|----------|--------| +| `linkedin_post` / `linkedin_page_post` | Image 5 MB; video 1 GB; PDF 100 MB | 10 minutes | JPG/PNG (GIF not accepted in the editor). Video MP4 or MOV. PDF alone | + +Images, a video, and a PDF cannot be mixed on one post. ### TikTok -| Content type | Media | Max files | Aspect | Notes | -|-------------|-------|-----------|--------|-------| -| `tiktok_video` | Required | 1 video | 9:16 | Short or long-form video | -| `tiktok_photo` | Required | Up to 35 images | 1:1 | Photo carousel — images only, no video | +Official: [Media Transfer Guide](https://developers.tiktok.com/doc/content-posting-api-media-transfer-guide). -### YouTube +| Type | Size | Duration | Format | +|------|------|----------|--------| +| `tiktok_video` | Video 1 GB | Per creator (`creator_info`) | MP4 or MOV. WebM is not accepted | +| `tiktok_photo` | Image 10 MB | — | JPEG/WebP (PNG is converted to JPEG on store). Up to 35 images | -| Content type | Media | Max files | Aspect | Notes | -|-------------|-------|-----------|--------|-------| -| `youtube_short` | Required | 1 video | 9:16 | Vertical short, up to 3 minutes | +### YouTube -### Threads +Official: [`videos.insert`](https://developers.google.com/youtube/v3/docs/videos/insert). Shorts length is a product rule: [3-minute Shorts](https://support.google.com/youtube/answer/15424877). -| Content type | Media | Max files | Notes | -|-------------|-------|-----------|-------| -| `threads_post` | Optional | Up to 10 images or 1 video | Text post with optional media | +| Type | Size | Duration | Format | Aspect | +|------|------|----------|--------|--------| +| `youtube_short` | Video 1 GB | 3 minutes | MP4 or MOV | 9:16 (0.50–0.60) | ### Pinterest -| Content type | Media | Max files | Aspect | Notes | -|-------------|-------|-----------|--------|-------| -| `pinterest_pin` | Required | 1 image | 2:3 | Standard image pin | -| `pinterest_video_pin` | Required | 1 video | 9:16 | Video pin | -| `pinterest_carousel` | Required | 2–5 images | 2:3 | Multi-image swipeable pin | +Official: [Creating boards and pins](https://developers.pinterest.com/docs/work-with-organic-content-and-users/create-boards-and-pins/), [Pinterest product specs](https://help.pinterest.com/en/business/article/pinterest-product-specs). + +| Type | Size | Duration | Format | Aspect | +|------|------|----------|--------|--------| +| `pinterest_pin` | Image 10 MB | — | JPEG/PNG | 2:3 | +| `pinterest_video_pin` | Video 1 GB | 15 minutes | MP4 or MOV | 9:16 | +| `pinterest_carousel` | Image 10 MB | — | JPEG/PNG, 2–5 images | 2:3 | ### Bluesky -| Content type | Media | Max files | Notes | -|-------------|-------|-----------|-------| -| `bluesky_post` | Optional | Up to 4 images or 1 video | Text post with optional media | +Official: [`app.bsky.embed.video`](https://github.com/bluesky-social/atproto/blob/main/lexicons/app/bsky/embed/video.json) (300 MB, MP4), [`app.bsky.embed.images`](https://github.com/bluesky-social/atproto/blob/main/lexicons/app/bsky/embed/images.json) (2 MB). + +| Type | Size | Duration | Format | +|------|------|----------|--------| +| `bluesky_post` | Image 2 MB; video 300 MB | 60 seconds | Images JPEG/PNG/GIF/WebP. Video **MP4 only** — MOV is blocked in the editor and API | + +Images and a video cannot be mixed (the embed is images XOR video). ### Mastodon -| Content type | Media | Max files | Notes | -|-------------|-------|-----------|-------| -| `mastodon_post` | Optional | Up to 4 images or 1 video | Text post with optional media | +Official: [Attachments](https://docs.joinmastodon.org/user/posting/#attachments) and [`Instance.media_attachments`](https://docs.joinmastodon.org/entities/Instance/). -### Telegram +| Type | Size | Duration | Format | +|------|------|----------|--------| +| `mastodon_post` | Image 10 MB; video 40 MB | — | JPEG/PNG/GIF/WebP; video MP4 or MOV | -| Content type | Media | Max files | Notes | -|-------------|-------|-----------|-------| -| `telegram_post` | Optional | Up to 10 images/videos | Text post; multiple media sent as an album | +Instance defaults vary. TryPost stays on 10 / 40 MB rather than assuming a 99 MB host. ### Discord -| Content type | Media | Max files | Notes | -|-------------|-------|-----------|-------| -| `discord_message` | Optional | Up to 10 images/videos | Channel message; supports mentions and rich embeds | +Official: [Uploading Files](https://docs.discord.com/developers/reference#uploading-files) (20 MiB default for bots). + +| Type | Size | Duration | Format | +|------|------|----------|--------| +| `discord_message` | Image 10 MB; video 20 MB | — | Any allowed upload type. GIF accepted. Stills are optimized; video and GIF go out as-is | + +### Telegram + +Official: [Sending files](https://core.telegram.org/bots/api#sending-files), [sendPhoto](https://core.telegram.org/bots/api#sendphoto), [sendVideo](https://core.telegram.org/bots/api#sendvideo). + +| Type | Size | Duration | Format | +|------|------|----------|--------| +| `telegram_post` | Image 5 MB; video 20 MB | — | JPEG/PNG/GIF/WebP; video MPEG4 (MP4 or MOV) | + +TryPost publishes Telegram media by **URL**, not multipart upload, so the caps are 5 MB (photo) and 20 MB (video) — not the 10 / 50 MB multipart figures. ## Media ordering @@ -145,7 +226,19 @@ Any S3-compatible service (MinIO, DigitalOcean Spaces, Backblaze B2) works under - Defaults: **10 MB** per image, **1 GB** per video, **100 MB** per PDF. Files over 1 MB are sent through the chunked upload endpoint via `Content-Range` headers. Self-hosters can raise the caps with `MEDIA_IMAGE_MAX_SIZE_MB` / `MEDIA_VIDEO_MAX_SIZE_MB` / `MEDIA_DOCUMENT_MAX_SIZE_MB`. + Cloud upload: **10 MB** per image, **1 GB** per video, **100 MB** per PDF. Many networks are tighter than that — see the [size catalog](#size-catalog-cloud). Files over 1 MB are sent through the chunked upload endpoint via `Content-Range` headers. Self-hosters can raise the upload caps with `MEDIA_IMAGE_MAX_SIZE_MB` / `MEDIA_VIDEO_MAX_SIZE_MB` / `MEDIA_DOCUMENT_MAX_SIZE_MB`. + + + An Instagram Reel may be at most **300 MB** (and 15 minutes). Meta pulls the file from a public URL (`video_url`); a ~900 MB file misses that window even though Cloud upload allows 1 GB. Compress or trim the clip, or pick a different network. Resumable / rupload is not available yet. + + + A **single** video on `instagram_feed` publishes as a Reel. Feed video is the carousel `VIDEO` slot: **100 MB / 60 seconds**. For anything longer, switch the content type to **Reel** (`instagram_reel`, 300 MB / 15 minutes). + + + TryPost sends Telegram photos and videos as a **URL**, and Telegram's URL path is 5 MB (photo) / 20 MB (video). Multipart upload would allow 10 / 50 MB — that is not the path we use. + + + No. Bluesky accepts **MP4 only**. The editor and API block MOV on `bluesky_post`. Export or remux the file as MP4. Yes — store the file in the [Asset Library](/knowledge-base/assets), then attach it with [`POST /posts/{post}/media/from-asset`](/api-reference/endpoint/attach-existing-asset) or MCP `attach-existing-asset-tool`. The post snapshot shares the library file path. You can also upload again via [`POST /posts/{post}/media`](/api-reference/endpoint/upload-media) or [`POST /posts/{post}/media/from-url`](/api-reference/endpoint/attach-media-from-url). @@ -154,6 +247,6 @@ Any S3-compatible service (MinIO, DigitalOcean Spaces, Backblaze B2) works under The media records are removed along with the post. - TryPost uploads media to social platforms as-is. Each platform applies its own compression and resizing rules afterwards. + On store, PNG and WebP become JPEG. On publish, most networks get a cropped or optimized JPEG (see [What TryPost does to your files](#what-trypost-does-to-your-files)). Videos are never transcoded. After that, each network may compress again. diff --git a/platforms/bluesky.mdx b/platforms/bluesky.mdx index 956e54c..04cb5da 100644 --- a/platforms/bluesky.mdx +++ b/platforms/bluesky.mdx @@ -24,6 +24,14 @@ TryPost supports posting to Bluesky. |------|-------------| | **Post** | Text with up to 4 optional images **or** 1 video | +## Media limits + +| `content_type` | Image | Video | Duration | Format | +|----------------|-------|-------|----------|--------| +| `bluesky_post` | 2 MB | 300 MB | 60 seconds | Images JPEG/PNG/GIF/WebP. Video **MP4 only** (MOV blocked) | + +Official specs: [`app.bsky.embed.video`](https://github.com/bluesky-social/atproto/blob/main/lexicons/app/bsky/embed/video.json), [`app.bsky.embed.images`](https://github.com/bluesky-social/atproto/blob/main/lexicons/app/bsky/embed/images.json). Full catalog: [Media](/knowledge-base/media). + ## Self-hosting setup No API credentials or environment variables are required for Bluesky. It works out of the box on any self-hosted instance. diff --git a/platforms/discord.mdx b/platforms/discord.mdx index ddf3581..c66d582 100644 --- a/platforms/discord.mdx +++ b/platforms/discord.mdx @@ -37,6 +37,14 @@ Only channels the bot can actually post in are shown — **text** and **announce |------|-------------| | **Message** (`discord_message`) | Text with up to 10 images/videos, optional mentions and rich embeds | +## Media limits + +| `content_type` | Image | Video | Format | +|----------------|-------|-------|--------| +| `discord_message` | 10 MB | 20 MB | Any allowed upload type. GIF accepted | + +Official specs: [Uploading Files](https://docs.discord.com/developers/reference#uploading-files) (20 MiB bot default). Full catalog: [Media](/knowledge-base/media). + Discord allows up to **2000** characters of message text. Images are optimized to Discord's limits; videos and GIFs are sent as-is. ### Mentions diff --git a/platforms/facebook.mdx b/platforms/facebook.mdx index 3449665..780b013 100644 --- a/platforms/facebook.mdx +++ b/platforms/facebook.mdx @@ -23,6 +23,16 @@ TryPost supports posting to Facebook pages. | **Reel** | 9:16 | Short-form vertical video | | **Story** | 9:16 | Temporary content (24 hours) | +## Media limits + +| `content_type` | Image | Video | Duration | Format | +|----------------|-------|-------|----------|--------| +| `facebook_post` | 4 MB | 1 GB | 240 minutes | Feed photos cropped to JPEG. Video MP4 or MOV | +| `facebook_reel` | — | 1 GB | 90 seconds | MP4 recommended | +| `facebook_story` | — | 1 GB | 60 seconds | MP4 recommended | + +Official specs: [Reels](https://developers.facebook.com/docs/video-api/guides/reels-publishing/), [Stories](https://developers.facebook.com/docs/page-stories-api/), [Video errors](https://developers.facebook.com/docs/video-api/reference/error-codes/). Full catalog: [Media](/knowledge-base/media). + ## OAuth scopes `public_profile`, `pages_show_list`, `pages_read_engagement`, `pages_manage_posts`, `read_insights` diff --git a/platforms/instagram.mdx b/platforms/instagram.mdx index 52f9d17..306845e 100644 --- a/platforms/instagram.mdx +++ b/platforms/instagram.mdx @@ -47,6 +47,16 @@ There is **no** separate `instagram_carousel` content type on posts. The AI Crea All three content types are available on both connection flavors. +## Media limits + +| `content_type` | Image | Video | Duration | Format | +|----------------|-------|-------|----------|--------| +| `instagram_feed` | 8 MB | 100 MB | 60 seconds | JPEG after store. Video MP4 or MOV | +| `instagram_reel` | — | 300 MB | 15 minutes | MOV or MP4 | +| `instagram_story` | 8 MB | 100 MB | 60 seconds | Same as feed; stills auto-fit to 9:16 | + +A single video on `instagram_feed` publishes as a Reel. Official specs: [IG User Media](https://developers.facebook.com/docs/instagram-platform/instagram-graph-api/reference/ig-user/media/). Full catalog: [Media](/knowledge-base/media). + Either flavor can be a [repurpose](/knowledge-base/repurposes) source. TryPost watches the account for new Reels, feed videos, or Stories you publish outside TryPost and republishes them to the destinations you pick. ## OAuth scopes diff --git a/platforms/linkedin.mdx b/platforms/linkedin.mdx index 7d28c0e..2e1e167 100644 --- a/platforms/linkedin.mdx +++ b/platforms/linkedin.mdx @@ -31,6 +31,14 @@ Each identity connects as its own social account. Personal profiles use `linkedin_post`; company pages use `linkedin_page_post`. +## Media limits + +| `content_type` | Image | Video | PDF | Duration | Format | +|----------------|-------|-------|-----|----------|--------| +| `linkedin_post` / `linkedin_page_post` | 5 MB | 1 GB | 100 MB | 10 minutes | JPG/PNG. Video MP4 or MOV. PDF alone | + +Official specs: [Videos](https://learn.microsoft.com/en-us/linkedin/marketing/community-management/shares/videos-api), [Images](https://learn.microsoft.com/en-us/linkedin/marketing/community-management/shares/images-api), [Documents](https://learn.microsoft.com/en-us/linkedin/marketing/community-management/shares/documents-api). Full catalog: [Media](/knowledge-base/media). + ## OAuth scopes | Connection | Scopes requested | diff --git a/platforms/mastodon.mdx b/platforms/mastodon.mdx index a4bf2b9..f3d54f9 100644 --- a/platforms/mastodon.mdx +++ b/platforms/mastodon.mdx @@ -21,6 +21,14 @@ TryPost supports posting to any Mastodon instance. |------|-------------| | **Post** | Text with up to 4 optional images or 1 video | +## Media limits + +| `content_type` | Image | Video | Format | +|----------------|-------|-------|--------| +| `mastodon_post` | 10 MB | 40 MB | JPEG/PNG/GIF/WebP; video MP4 or MOV | + +Official specs: [Attachments](https://docs.joinmastodon.org/user/posting/#attachments), [`Instance.media_attachments`](https://docs.joinmastodon.org/entities/Instance/). Full catalog: [Media](/knowledge-base/media). + ## OAuth scopes `read:accounts`, `write:statuses`, `write:media` diff --git a/platforms/pinterest.mdx b/platforms/pinterest.mdx index f370061..19b916f 100644 --- a/platforms/pinterest.mdx +++ b/platforms/pinterest.mdx @@ -31,6 +31,16 @@ If neither a per-post `board_id` nor a default board is set, publishing fails wi | **Video Pin** | 9:16 | Video pin, 4 seconds to 15 minutes (1 video, required) | | **Carousel** | 2:3 | Multi-image pin (up to 5 images, required) | +## Media limits + +| `content_type` | Image | Video | Duration | Format | +|----------------|-------|-------|----------|--------| +| `pinterest_pin` | 10 MB | — | — | JPEG/PNG | +| `pinterest_video_pin` | — | 1 GB | 15 minutes | MP4 or MOV | +| `pinterest_carousel` | 10 MB | — | — | JPEG/PNG, 2–5 images | + +Official specs: [Creating boards and pins](https://developers.pinterest.com/docs/work-with-organic-content-and-users/create-boards-and-pins/), [Product specs](https://help.pinterest.com/en/business/article/pinterest-product-specs). Full catalog: [Media](/knowledge-base/media). + ## OAuth scopes `boards:read`, `boards:write`, `pins:read`, `pins:write`, `user_accounts:read` diff --git a/platforms/telegram.mdx b/platforms/telegram.mdx index 7ed3b5f..68d5715 100644 --- a/platforms/telegram.mdx +++ b/platforms/telegram.mdx @@ -34,6 +34,14 @@ Posting it somewhere else is rejected with *Post the command in the channel you |------|-------------| | **Post** (`telegram_post`) | Text with up to 10 images/videos (multiple media are sent as an album) | +## Media limits + +| `content_type` | Image | Video | Format | +|----------------|-------|-------|--------| +| `telegram_post` | 5 MB | 20 MB | JPEG/PNG/GIF/WebP; video MPEG4 (MP4 or MOV) | + +These are Telegram's **URL** limits (TryPost does not use multipart). Official specs: [Sending files](https://core.telegram.org/bots/api#sending-files). Full catalog: [Media](/knowledge-base/media). + Telegram allows up to **4096** characters of text. Media captions are capped at **1024**, so a longer post is sent as the media followed by a separate text message. Formatting (bold, italic, links, `code`) and plain `@username` mentions are preserved — Telegram auto-links public usernames. ## Analytics diff --git a/platforms/threads.mdx b/platforms/threads.mdx index 59881f9..7315cfe 100644 --- a/platforms/threads.mdx +++ b/platforms/threads.mdx @@ -20,6 +20,14 @@ TryPost supports posting to Threads. |------|-------------| | **Post** | Text with up to 10 optional images **or** 1 video | +## Media limits + +| `content_type` | Image | Video | Duration | Format | +|----------------|-------|-------|----------|--------| +| `threads_post` | 8 MB | 1 GB | 5 minutes | JPEG/PNG; video MOV or MP4. No crop | + +Official specs: [Overview](https://developers.facebook.com/docs/threads/overview/), [Posts](https://developers.facebook.com/docs/threads/posts/). Full catalog: [Media](/knowledge-base/media). + ## OAuth scopes `threads_basic`, `threads_content_publish`, `threads_manage_insights` diff --git a/platforms/tiktok.mdx b/platforms/tiktok.mdx index 9a513d5..8967121 100644 --- a/platforms/tiktok.mdx +++ b/platforms/tiktok.mdx @@ -21,6 +21,15 @@ TryPost supports posting videos and photo carousels to TikTok. | **Video** | `tiktok_video` | 9:16 | Short or long-form video (1 video, required) | | **Photo carousel** | `tiktok_photo` | 1:1 | Multi-image post — up to 35 images per carousel | +## Media limits + +| `content_type` | Image | Video | Duration | Format | +|----------------|-------|-------|----------|--------| +| `tiktok_video` | — | 1 GB | Per creator | MP4 or MOV (no WebM) | +| `tiktok_photo` | 10 MB | — | — | JPEG/WebP, up to 35 images | + +Official specs: [Media Transfer Guide](https://developers.tiktok.com/doc/content-posting-api-media-transfer-guide). Full catalog: [Media](/knowledge-base/media). + ## Per-post options TikTok exposes extra publishing options that you can set per post in the editor sidebar (or via `platforms[].meta` on the API): diff --git a/platforms/x-twitter.mdx b/platforms/x-twitter.mdx index 4fcde07..dc1d9bf 100644 --- a/platforms/x-twitter.mdx +++ b/platforms/x-twitter.mdx @@ -20,6 +20,14 @@ TryPost supports posting to X (formerly Twitter) accounts. |------|-------------| | **Post** | Text with up to 4 images or 1 video | +## Media limits + +| `content_type` | Image | Video | Duration | Format | +|----------------|-------|-------|----------|--------| +| `x_post` | 5 MB | 1 GB | 20 minutes | JPG/PNG/GIF/WebP; video H.264 (MP4 or MOV) | + +These are Post (`tweet_video`) limits. Official specs: [Media best practices](https://docs.x.com/x-api/media/quickstart/best-practices). Full catalog: [Media](/knowledge-base/media). + ## Links in posts X charges much more to deliver a post that carries a link, and shows it to fewer people. To keep a post out of that bracket, TryPost publishes the X version of a post with its links written non-clickable: `https://www.example.com/pricing` goes out as `example(.)com/pricing`. diff --git a/platforms/youtube.mdx b/platforms/youtube.mdx index d20604c..e50d15a 100644 --- a/platforms/youtube.mdx +++ b/platforms/youtube.mdx @@ -21,6 +21,14 @@ TryPost supports uploading YouTube Shorts. |------|-------------|-------------| | **Short** | 9:16 | Vertical video up to 3 minutes (required) | +## Media limits + +| `content_type` | Video | Duration | Format | +|----------------|-------|----------|--------| +| `youtube_short` | 1 GB | 3 minutes | MP4 or MOV | + +Official specs: [`videos.insert`](https://developers.google.com/youtube/v3/docs/videos/insert), [3-minute Shorts](https://support.google.com/youtube/answer/15424877). Full catalog: [Media](/knowledge-base/media). + ## OAuth scopes `https://www.googleapis.com/auth/youtube.upload`, `https://www.googleapis.com/auth/youtube.readonly`, `https://www.googleapis.com/auth/youtube.force-ssl`, `https://www.googleapis.com/auth/yt-analytics.readonly` From 6d9b934f0b8714676773988cd9b82d4b511c95e3 Mon Sep 17 00:00:00 2001 From: Paulo Castellano Date: Fri, 11 Sep 2026 22:35:07 -0300 Subject: [PATCH 2/5] docs: correct media limits (Bluesky 10 min, X 8 GB, TikTok 10 min) and document server-side enforcement - Bluesky: lexicon decimal bytes, 10-minute limit with the official announcement as source, BLUESKY_VIDEO_MAX_BYTES note. - X: 8 GB / 20 min tweet_video default (Premium 16 GB / 125 min); 1 GB is the Cloud cap, not an X limit; never amplify_video. - TikTok: 10-minute API ceiling, creator_info may lower it. - Instagram feed: 100 MB / 60 s is TryPost's conservative rule, single video publishes through the Reels container. - New section on publish/schedule server-side checks (kind, GIF/MOV, size, duration) plus update-post and list-content-types notes. --- api-reference/endpoint/list-content-types.mdx | 8 ++-- api-reference/endpoint/update-post.mdx | 1 + knowledge-base/media.mdx | 40 +++++++++++++------ platforms/bluesky.mdx | 4 +- platforms/instagram.mdx | 2 +- platforms/tiktok.mdx | 2 +- platforms/x-twitter.mdx | 4 +- 7 files changed, 40 insertions(+), 21 deletions(-) diff --git a/api-reference/endpoint/list-content-types.mdx b/api-reference/endpoint/list-content-types.mdx index ffb5d50..70aa83c 100644 --- a/api-reference/endpoint/list-content-types.mdx +++ b/api-reference/endpoint/list-content-types.mdx @@ -42,11 +42,13 @@ Returns `{ "platforms": [ ... ] }` — one object per social platform. | `accepts_gif` | Whether GIF is accepted as an image. | | `accepts_mov` | Whether QuickTime/MOV is accepted. `false` on Bluesky (MP4 only). | | `forbids_mixed_media` | When `true`, do not mix images and videos in one post. | -| `max_video_duration_sec` | Max video length in seconds, or `null`. | -| `max_image_bytes` | Max image size in bytes, or `null`. | -| `max_video_bytes` | Max video size in bytes, or `null`. | +| `max_video_duration_sec` | Max video length in seconds, or `null`. TikTok reports the 10-minute API ceiling; `creator_info` may lower it per account. | +| `max_image_bytes` | Max image size in bytes, or `null`. Already clamped to the instance upload cap. | +| `max_video_bytes` | Max video size in bytes, or `null`. Already clamped to the instance upload cap (Cloud: 1 GB, so X's 8 GB reads as 1 GB here). | | `max_document_bytes` | Max PDF size in bytes, or `null`. | +Byte and duration caps are enforced server-side on publish/schedule as well as in the editor — see [Media → Enforced on the server](/knowledge-base/media#enforced-on-the-server-not-just-in-the-editor). + ### Current `content_type` values (20) | Platform | Values | diff --git a/api-reference/endpoint/update-post.mdx b/api-reference/endpoint/update-post.mdx index 6a2d4ad..5cb0a0e 100644 --- a/api-reference/endpoint/update-post.mdx +++ b/api-reference/endpoint/update-post.mdx @@ -67,6 +67,7 @@ description: "Update a post's content, schedule, enabled platforms, or labels - On update, `meta` is **merged** into the platform's existing object. Send a key as `null` to remove it (e.g. `"title": null`). - Required-to-publish keys are enforced on this request when `status` is `scheduled` or `publishing` **and** you include a `platforms[]` array in the body (each submitted row is checked). Drafts are not checked. A missing key returns `422` on `platforms.{i}.meta.{field}` (e.g. `platforms.0.meta.channel_id`). - If you publish with only `{ "status": "publishing" }` (no `platforms[]`), this endpoint does **not** re-validate stored meta — ensure `board_id` / `privacy_level` / `channel_id` were saved earlier. The MCP `publish-post-tool` always validates stored meta before publishing. +- **Media compatibility is always re-checked** on `scheduled` / `publishing`, with or without `platforms[]`: every enabled platform's effective `content_type` is validated against the post's effective media (media kind, GIF/MOV acceptance, byte cap via `size`, and video duration when known). A failure is `422` on `platforms.{i}.content_type`, e.g. `Reel accepts a video of up to 300 MB (yours is 900.0 MB).` — see [Media → Enforced on the server](/knowledge-base/media#enforced-on-the-server-not-just-in-the-editor). - Enum-like fields are **JSON strings** — send the exact literal (e.g. `"privacy_level": "PUBLIC_TO_EVERYONE"`), not an integer or a different casing. - Platforms with **no** `meta` keys: X, YouTube, Threads, Bluesky, Mastodon, Telegram. diff --git a/knowledge-base/media.mdx b/knowledge-base/media.mdx index 5900c72..2bddad7 100644 --- a/knowledge-base/media.mdx +++ b/knowledge-base/media.mdx @@ -52,6 +52,17 @@ Signed upload URLs are single-use and expire after **15 minutes** by default (`M **MOV:** accepted everywhere except Bluesky. Bluesky's video lexicon is **MP4 only** — the editor and API reject MOV on `bluesky_post`. +## Enforced on the server, not just in the editor + +Every publish or schedule — dashboard, [`PUT /posts/{post}`](/api-reference/endpoint/update-post) with `status: publishing|scheduled`, and MCP [`publish-post-tool`](/ai/tools-reference#posts) — re-checks each enabled platform's `content_type` against the post's media and fails with a validation error on `platforms..content_type` when: + +- the media kind is not supported (a video on `pinterest_pin`, a PDF outside LinkedIn, images mixed with a video where the network takes one or the other); +- a **GIF** or **MOV** lands on a type that does not accept it; +- a file's `size` is over the type's byte cap (the ~900 MB Instagram Reel is refused here, before Meta ever sees it); +- a video's duration is over the type's cap — when the duration is known. Duration is measured in the browser when you upload from the dashboard; a file attached through the REST API or a signed upload URL carries no duration, so only its size is checked. + +Drafts are never blocked: the checks run on publish and schedule only. Media attached before this check existed may lack `size` and is not size-checked until re-attached. + ## Size catalog (Cloud) Numbers below are what the editor and [`GET /content-types`](/api-reference/endpoint/list-content-types) enforce after the Cloud hard cap (10 MB image / 1 GB video). A dash means that media kind is not accepted for the type. @@ -71,14 +82,14 @@ Numbers below are what the editor and [`GET /content-types`](/api-reference/endp | `pinterest_carousel` | 10 MB | — | — | | `x_post` | 5 MB | 1 GB | 20 minutes | | `threads_post` | 8 MB | 1 GB | 5 minutes | -| `bluesky_post` | 2 MB | 300 MB | 60 seconds | +| `bluesky_post` | 2 MB | 300 MB | 10 minutes | | `mastodon_post` | 10 MB | 40 MB | — | -| `tiktok_video` | — | 1 GB | per creator (`creator_info`) | +| `tiktok_video` | — | 1 GB | 10 minutes | | `tiktok_photo` | 10 MB | — | — | | `discord_message` | 10 MB | 20 MB | — | | `telegram_post` | 5 MB | 20 MB | — | -LinkedIn PDF posts: **100 MB**. TikTok video duration is not a fixed editor cap — TikTok returns it per creator. +LinkedIn PDF posts: **100 MB**. Bluesky's 2 MB / 300 MB are the lexicon's exact decimal values (2 000 000 / 300 000 000 bytes), not MiB. TikTok's 10 minutes is the developer-upload ceiling; TikTok may return a lower per-creator limit (`creator_info`), which is enforced at publish. There is **no** `linkedin_carousel`, `linkedin_page_carousel`, or `instagram_carousel` content type on posts. Multi-image Instagram posts use `instagram_feed`. LinkedIn multi-image / PDF posts use `linkedin_post` / `linkedin_page_post` (format is inferred from the attached media; optional `meta.document_title` for PDFs). @@ -96,7 +107,7 @@ Official: [IG User Media — Image, Reel, Story specs](https://developers.facebo | `instagram_reel` | Video 300 MB | 15 minutes | MOV or MP4 | 9:16 (0.50–0.60) | | `instagram_story` | Image 8 MB; video 100 MB | 60 seconds | Same as feed. Stories auto-fit stills onto 9:16 | 9:16 (0.50–0.60) | -A **single video** attached to `instagram_feed` publishes as a Reel. Use `instagram_reel` for anything longer than 60 seconds or larger than 100 MB (up to 300 MB / 15 minutes). Feed video is the carousel `media_type=VIDEO` path, not the Reel container. +Instagram has no plain feed-video container any more: a **single video** on `instagram_feed` is published through the Reels container, and a video inside a multi-item feed post goes out as a carousel child (`media_type=VIDEO`). Meta only documents the Reel spec, so the **100 MB / 60 seconds** on `instagram_feed` is TryPost's conservative rule (same as Stories), not a Meta number. Pick `instagram_reel` for anything longer or larger — it unlocks the official 300 MB / 15 minutes. ### Facebook @@ -122,9 +133,9 @@ Official: [Media best practices](https://docs.x.com/x-api/media/quickstart/best- | Type | Size | Duration | Format | |------|------|----------|--------| -| `x_post` | Image 5 MB; video 1 GB | 20 minutes | JPG/PNG/GIF/WebP; video H.264 (MP4 or MOV). Stills become JPEG on publish; GIF stays GIF | +| `x_post` | Image 5 MB; video 1 GB (Cloud cap — X allows 8 GB) | 20 minutes | JPG/PNG/GIF/WebP; video H.264 (MP4 or MOV). Stills become JPEG on publish; GIF stays GIF | -These are **Post** (`tweet_video`) limits, not Direct Message (`dm_video`) limits. +These are **Post** (`tweet_video`) limits — 8 GB / 20 minutes is the default entitlement, X Premium raises it to 16 GB / 125 minutes — not Direct Message (`dm_video`) limits, and not the `amplify_video` Ads category. TryPost always uploads Post videos as `tweet_video`. The 1 GB you see in the editor is the Cloud upload cap, not an X limit; self-hosted installs that raise `MEDIA_VIDEO_MAX_SIZE_MB` get up to 8 GB on X. ### LinkedIn @@ -142,8 +153,10 @@ Official: [Media Transfer Guide](https://developers.tiktok.com/doc/content-posti | Type | Size | Duration | Format | |------|------|----------|--------| -| `tiktok_video` | Video 1 GB | Per creator (`creator_info`) | MP4 or MOV. WebM is not accepted | -| `tiktok_photo` | Image 10 MB | — | JPEG/WebP (PNG is converted to JPEG on store). Up to 35 images | +| `tiktok_video` | Video 1 GB (Cloud cap — TikTok allows 4 GB) | 10 minutes | MP4 or MOV. WebM is not accepted | +| `tiktok_photo` | Image 10 MB (TikTok allows 20 MB) | — | JPEG/WebP (PNG is converted to JPEG on store). Up to 35 images | + +10 minutes is TikTok's ceiling for API uploads. `creator_info` can return a shorter `max_video_post_duration_sec` for a given account; the editor shows it and publishing enforces it. ### YouTube @@ -165,13 +178,13 @@ Official: [Creating boards and pins](https://developers.pinterest.com/docs/work- ### Bluesky -Official: [`app.bsky.embed.video`](https://github.com/bluesky-social/atproto/blob/main/lexicons/app/bsky/embed/video.json) (300 MB, MP4), [`app.bsky.embed.images`](https://github.com/bluesky-social/atproto/blob/main/lexicons/app/bsky/embed/images.json) (2 MB). +Official: [`app.bsky.embed.video`](https://github.com/bluesky-social/atproto/blob/main/lexicons/app/bsky/embed/video.json) (`maxSize` 300 000 000, `accept: video/mp4`), [`app.bsky.embed.images`](https://github.com/bluesky-social/atproto/blob/main/lexicons/app/bsky/embed/images.json) (`maxSize` 2 000 000). The lexicon carries no duration; the 10-minute limit is the video service's, [announced by @bsky.app on 26 August 2026](https://techcrunch.com/2026/08/26/bluesky-now-lets-you-upload-10-minute-long-videos/). | Type | Size | Duration | Format | |------|------|----------|--------| -| `bluesky_post` | Image 2 MB; video 300 MB | 60 seconds | Images JPEG/PNG/GIF/WebP. Video **MP4 only** — MOV is blocked in the editor and API | +| `bluesky_post` | Image 2 MB; video 300 MB (decimal bytes) | 10 minutes | Images JPEG/PNG/GIF/WebP. Video **MP4 only** — MOV is blocked in the editor and API | -Images and a video cannot be mixed (the embed is images XOR video). +Images and a video cannot be mixed (the embed is images XOR video). Self-hosted: `BLUESKY_VIDEO_MAX_BYTES` is the publisher's skip threshold and defaults to the same 300 000 000 — leave it alone unless the lexicon changes. ### Mastodon @@ -232,7 +245,10 @@ Any S3-compatible service (MinIO, DigitalOcean Spaces, Backblaze B2) works under An Instagram Reel may be at most **300 MB** (and 15 minutes). Meta pulls the file from a public URL (`video_url`); a ~900 MB file misses that window even though Cloud upload allows 1 GB. Compress or trim the clip, or pick a different network. Resumable / rupload is not available yet. - A **single** video on `instagram_feed` publishes as a Reel. Feed video is the carousel `VIDEO` slot: **100 MB / 60 seconds**. For anything longer, switch the content type to **Reel** (`instagram_reel`, 300 MB / 15 minutes). + `instagram_feed` keeps video at **100 MB / 60 seconds**. That is TryPost's conservative rule (the same as Stories), not a Meta figure — Meta only documents the Reel spec, and a single feed video is published through the Reels container anyway. Switch the content type to **Reel** (`instagram_reel`) for anything longer: up to 300 MB / 15 minutes. + + + Upload checks the Cloud hard cap only; publish and schedule check the per-`content_type` cap and format rules (see [Enforced on the server](#enforced-on-the-server-not-just-in-the-editor)). The response is a `422` with the message under `errors["platforms..content_type"]`, e.g. `Reel accepts a video of up to 300 MB (yours is 900.0 MB).` Fix the file, or change the platform's `content_type`, then publish again. TryPost sends Telegram photos and videos as a **URL**, and Telegram's URL path is 5 MB (photo) / 20 MB (video). Multipart upload would allow 10 / 50 MB — that is not the path we use. diff --git a/platforms/bluesky.mdx b/platforms/bluesky.mdx index 04cb5da..02fadac 100644 --- a/platforms/bluesky.mdx +++ b/platforms/bluesky.mdx @@ -28,9 +28,9 @@ TryPost supports posting to Bluesky. | `content_type` | Image | Video | Duration | Format | |----------------|-------|-------|----------|--------| -| `bluesky_post` | 2 MB | 300 MB | 60 seconds | Images JPEG/PNG/GIF/WebP. Video **MP4 only** (MOV blocked) | +| `bluesky_post` | 2 MB | 300 MB | 10 minutes | Images JPEG/PNG/GIF/WebP. Video **MP4 only** (MOV blocked) | -Official specs: [`app.bsky.embed.video`](https://github.com/bluesky-social/atproto/blob/main/lexicons/app/bsky/embed/video.json), [`app.bsky.embed.images`](https://github.com/bluesky-social/atproto/blob/main/lexicons/app/bsky/embed/images.json). Full catalog: [Media](/knowledge-base/media). +Sizes are the lexicon's decimal values (2 000 000 / 300 000 000 bytes). Official specs: [`app.bsky.embed.video`](https://github.com/bluesky-social/atproto/blob/main/lexicons/app/bsky/embed/video.json), [`app.bsky.embed.images`](https://github.com/bluesky-social/atproto/blob/main/lexicons/app/bsky/embed/images.json); the 10-minute limit was [announced by Bluesky on 26 August 2026](https://techcrunch.com/2026/08/26/bluesky-now-lets-you-upload-10-minute-long-videos/). Full catalog: [Media](/knowledge-base/media). ## Self-hosting setup diff --git a/platforms/instagram.mdx b/platforms/instagram.mdx index 306845e..341cf46 100644 --- a/platforms/instagram.mdx +++ b/platforms/instagram.mdx @@ -55,7 +55,7 @@ All three content types are available on both connection flavors. | `instagram_reel` | — | 300 MB | 15 minutes | MOV or MP4 | | `instagram_story` | 8 MB | 100 MB | 60 seconds | Same as feed; stills auto-fit to 9:16 | -A single video on `instagram_feed` publishes as a Reel. Official specs: [IG User Media](https://developers.facebook.com/docs/instagram-platform/instagram-graph-api/reference/ig-user/media/). Full catalog: [Media](/knowledge-base/media). +A single video on `instagram_feed` publishes through the Reels container; the 100 MB / 60 seconds on `instagram_feed` is TryPost's conservative rule (Meta only documents the Reel spec) — use `instagram_reel` for longer clips. Official specs: [IG User Media](https://developers.facebook.com/docs/instagram-platform/instagram-graph-api/reference/ig-user/media/). Full catalog: [Media](/knowledge-base/media). Either flavor can be a [repurpose](/knowledge-base/repurposes) source. TryPost watches the account for new Reels, feed videos, or Stories you publish outside TryPost and republishes them to the destinations you pick. diff --git a/platforms/tiktok.mdx b/platforms/tiktok.mdx index 8967121..e7e65c6 100644 --- a/platforms/tiktok.mdx +++ b/platforms/tiktok.mdx @@ -25,7 +25,7 @@ TryPost supports posting videos and photo carousels to TikTok. | `content_type` | Image | Video | Duration | Format | |----------------|-------|-------|----------|--------| -| `tiktok_video` | — | 1 GB | Per creator | MP4 or MOV (no WebM) | +| `tiktok_video` | — | 1 GB (Cloud cap; TikTok allows 4 GB) | 10 minutes, or less if `creator_info` says so | MP4 or MOV (no WebM) | | `tiktok_photo` | 10 MB | — | — | JPEG/WebP, up to 35 images | Official specs: [Media Transfer Guide](https://developers.tiktok.com/doc/content-posting-api-media-transfer-guide). Full catalog: [Media](/knowledge-base/media). diff --git a/platforms/x-twitter.mdx b/platforms/x-twitter.mdx index dc1d9bf..4ed3758 100644 --- a/platforms/x-twitter.mdx +++ b/platforms/x-twitter.mdx @@ -24,9 +24,9 @@ TryPost supports posting to X (formerly Twitter) accounts. | `content_type` | Image | Video | Duration | Format | |----------------|-------|-------|----------|--------| -| `x_post` | 5 MB | 1 GB | 20 minutes | JPG/PNG/GIF/WebP; video H.264 (MP4 or MOV) | +| `x_post` | 5 MB | 1 GB (Cloud cap; X allows 8 GB) | 20 minutes | JPG/PNG/GIF/WebP; video H.264 (MP4 or MOV) | -These are Post (`tweet_video`) limits. Official specs: [Media best practices](https://docs.x.com/x-api/media/quickstart/best-practices). Full catalog: [Media](/knowledge-base/media). +These are Post (`tweet_video`) limits — 8 GB / 20 minutes by default, 16 GB / 125 minutes on X Premium — not DM or Ads (`amplify_video`) limits. Official specs: [Media best practices](https://docs.x.com/x-api/media/quickstart/best-practices). Full catalog: [Media](/knowledge-base/media). ## Links in posts From 5d249031aff96b81123ce95391f12a9d019bdb0a Mon Sep 17 00:00:00 2001 From: Paulo Castellano Date: Fri, 11 Sep 2026 22:47:58 -0300 Subject: [PATCH 3/5] =?UTF-8?q?docs:=20WebM=20wording=20=E2=80=94=20TikTok?= =?UTF-8?q?=20would=20accept=20it,=20TryPost's=20upload=20allow-list=20doe?= =?UTF-8?q?s=20not?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- knowledge-base/media.mdx | 4 ++-- platforms/tiktok.mdx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/knowledge-base/media.mdx b/knowledge-base/media.mdx index 2bddad7..1cb970d 100644 --- a/knowledge-base/media.mdx +++ b/knowledge-base/media.mdx @@ -19,7 +19,7 @@ You can attach media in four ways (same MIME allow-list for uploads): - [`POST /uploads/{token}`](/api-reference/endpoint/request-media-upload) — one-shot signed URL (MCP [`request-media-upload-tool`](/ai/tools-reference#posts)). - [`POST /posts/{post}/media/from-asset`](/api-reference/endpoint/attach-existing-asset) — reuse a file already in the [Asset Library](/knowledge-base/assets) (`asset_id`). MCP: [`attach-existing-asset-tool`](/ai/tools-reference#attach-existing-asset-tool). -WebM is intentionally excluded — every major social platform rejects it, so accepting it would just produce platform-specific publish failures. +WebM is intentionally excluded — most networks reject it (TikTok and Bluesky would transcode it, the rest refuse it), so accepting it would just produce platform-specific publish failures. ## Upload limits @@ -153,7 +153,7 @@ Official: [Media Transfer Guide](https://developers.tiktok.com/doc/content-posti | Type | Size | Duration | Format | |------|------|----------|--------| -| `tiktok_video` | Video 1 GB (Cloud cap — TikTok allows 4 GB) | 10 minutes | MP4 or MOV. WebM is not accepted | +| `tiktok_video` | Video 1 GB (Cloud cap — TikTok allows 4 GB) | 10 minutes | MP4 or MOV (TryPost does not accept WebM uploads, although TikTok would) | | `tiktok_photo` | Image 10 MB (TikTok allows 20 MB) | — | JPEG/WebP (PNG is converted to JPEG on store). Up to 35 images | 10 minutes is TikTok's ceiling for API uploads. `creator_info` can return a shorter `max_video_post_duration_sec` for a given account; the editor shows it and publishing enforces it. diff --git a/platforms/tiktok.mdx b/platforms/tiktok.mdx index e7e65c6..42f0649 100644 --- a/platforms/tiktok.mdx +++ b/platforms/tiktok.mdx @@ -25,7 +25,7 @@ TryPost supports posting videos and photo carousels to TikTok. | `content_type` | Image | Video | Duration | Format | |----------------|-------|-------|----------|--------| -| `tiktok_video` | — | 1 GB (Cloud cap; TikTok allows 4 GB) | 10 minutes, or less if `creator_info` says so | MP4 or MOV (no WebM) | +| `tiktok_video` | — | 1 GB (Cloud cap; TikTok allows 4 GB) | 10 minutes, or less if `creator_info` says so | MP4 or MOV (TryPost does not accept WebM uploads) | | `tiktok_photo` | 10 MB | — | — | JPEG/WebP, up to 35 images | Official specs: [Media Transfer Guide](https://developers.tiktok.com/doc/content-posting-api-media-transfer-guide). Full catalog: [Media](/knowledge-base/media). From aa32a5310558d8c2ce31ada8cd99ccb78b90c740 Mon Sep 17 00:00:00 2001 From: Paulo Castellano Date: Sat, 12 Sep 2026 08:53:52 -0300 Subject: [PATCH 4/5] Video duration is read on the server for every upload path --- api-reference/endpoint/attach-media-from-url.mdx | 2 +- api-reference/endpoint/request-media-upload.mdx | 2 +- api-reference/endpoint/update-post.mdx | 2 +- api-reference/endpoint/upload-media.mdx | 2 +- knowledge-base/media.mdx | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/api-reference/endpoint/attach-media-from-url.mdx b/api-reference/endpoint/attach-media-from-url.mdx index 803f220..9c3f9d8 100644 --- a/api-reference/endpoint/attach-media-from-url.mdx +++ b/api-reference/endpoint/attach-media-from-url.mdx @@ -41,7 +41,7 @@ For uploading a file directly from your machine instead of fetching a URL, use [ - The post must belong to the caller's current workspace; otherwise the response is `404`. - Allowed media types are **intersected with the platforms enabled on the post**. If an enabled platform doesn't support the file type (e.g. video on a platform that's image-only), that file is rejected and listed in `failed_urls`. -- Successful attachments are appended to the post's `media[]` array (image `alt` becomes `media[].meta.alt_text`). +- Successful attachments are appended to the post's `media[]` array with `size` and `meta` (image `alt` becomes `media[].meta.alt_text`; videos carry `meta.duration` read from the file). Per-network size, duration, GIF and MOV caps are enforced when the post is scheduled or published — see [Media → Enforced on the server](/knowledge-base/media#enforced-on-the-server-not-just-in-the-editor). ## Response diff --git a/api-reference/endpoint/request-media-upload.mdx b/api-reference/endpoint/request-media-upload.mdx index dbffed5..124f52f 100644 --- a/api-reference/endpoint/request-media-upload.mdx +++ b/api-reference/endpoint/request-media-upload.mdx @@ -49,7 +49,7 @@ Send as `multipart/form-data` with a single `media` field. The FormRequest upper bound is the video ceiling; the per-type cap is enforced after MIME detection. MIME is detected from the file's magic bytes (not the extension or `Content-Type` header). - `request-media-upload-tool` also returns these limits as `max_bytes` (video ceiling) and `max_bytes_by_type`. + `request-media-upload-tool` also returns these limits as `max_bytes` (video ceiling) and `max_bytes_by_type`. These are the workspace-wide ceilings; each network's own size, duration, GIF and MOV caps (`list-content-types-tool`) are enforced when the post is scheduled or published. A video's `duration` is read from the file on the server and stored in `meta`. ## Authentication diff --git a/api-reference/endpoint/update-post.mdx b/api-reference/endpoint/update-post.mdx index 5cb0a0e..f4d624a 100644 --- a/api-reference/endpoint/update-post.mdx +++ b/api-reference/endpoint/update-post.mdx @@ -67,7 +67,7 @@ description: "Update a post's content, schedule, enabled platforms, or labels - On update, `meta` is **merged** into the platform's existing object. Send a key as `null` to remove it (e.g. `"title": null`). - Required-to-publish keys are enforced on this request when `status` is `scheduled` or `publishing` **and** you include a `platforms[]` array in the body (each submitted row is checked). Drafts are not checked. A missing key returns `422` on `platforms.{i}.meta.{field}` (e.g. `platforms.0.meta.channel_id`). - If you publish with only `{ "status": "publishing" }` (no `platforms[]`), this endpoint does **not** re-validate stored meta — ensure `board_id` / `privacy_level` / `channel_id` were saved earlier. The MCP `publish-post-tool` always validates stored meta before publishing. -- **Media compatibility is always re-checked** on `scheduled` / `publishing`, with or without `platforms[]`: every enabled platform's effective `content_type` is validated against the post's effective media (media kind, GIF/MOV acceptance, byte cap via `size`, and video duration when known). A failure is `422` on `platforms.{i}.content_type`, e.g. `Reel accepts a video of up to 300 MB (yours is 900.0 MB).` — see [Media → Enforced on the server](/knowledge-base/media#enforced-on-the-server-not-just-in-the-editor). +- **Media compatibility is always re-checked** on `scheduled` / `publishing`, with or without `platforms[]`: every enabled platform's effective `content_type` is validated against the post's effective media (media kind, GIF/MOV acceptance, byte cap via `size`, and video duration read from the file on upload). A failure is `422` on `platforms.{i}.content_type`, e.g. `Reel accepts a video of up to 300 MB (yours is 900.0 MB).` — see [Media → Enforced on the server](/knowledge-base/media#enforced-on-the-server-not-just-in-the-editor). - Enum-like fields are **JSON strings** — send the exact literal (e.g. `"privacy_level": "PUBLIC_TO_EVERYONE"`), not an integer or a different casing. - Platforms with **no** `meta` keys: X, YouTube, Threads, Bluesky, Mastodon, Telegram. diff --git a/api-reference/endpoint/upload-media.mdx b/api-reference/endpoint/upload-media.mdx index c50d7b9..b992c75 100644 --- a/api-reference/endpoint/upload-media.mdx +++ b/api-reference/endpoint/upload-media.mdx @@ -30,7 +30,7 @@ Send as `multipart/form-data` with a single `media` field. - The file's MIME type is **intersected with the platforms enabled on the post**. For example, uploading an image to a TikTok-only post returns `422` unless the post targets `tiktok_photo`. Uploading a PDF only succeeds on platforms that accept documents (e.g. LinkedIn `linkedin_post`). - Per-type size caps are enforced after MIME detection. The FormRequest uses the video ceiling as an overall bound; per-type limits still apply. - PNG and WebP still images are normalized to **JPEG (q100)** at storage time for universal platform compatibility. GIF is preserved (animation kept for X / Bluesky / Mastodon / Telegram / Discord). MP4, MOV, and PDF are stored as-is. -- The new media is stored under `medias/{uuid}.{ext}` on the configured filesystem disk (`local`, `s3`, or `r2`) and appended to the post's `media[]` array. +- The new media is stored under `medias/{uuid}.{ext}` on the configured filesystem disk (`local`, `s3`, or `r2`) and appended to the post's `media[]` array with its `size` and `meta` (image `width`/`height`, video `duration` in seconds read from the file). Per-network size, duration, GIF and MOV caps are enforced when the post is scheduled or published — see [Media → Enforced on the server](/knowledge-base/media#enforced-on-the-server-not-just-in-the-editor). ## Response diff --git a/knowledge-base/media.mdx b/knowledge-base/media.mdx index 1cb970d..670da2b 100644 --- a/knowledge-base/media.mdx +++ b/knowledge-base/media.mdx @@ -59,7 +59,7 @@ Every publish or schedule — dashboard, [`PUT /posts/{post}`](/api-reference/en - the media kind is not supported (a video on `pinterest_pin`, a PDF outside LinkedIn, images mixed with a video where the network takes one or the other); - a **GIF** or **MOV** lands on a type that does not accept it; - a file's `size` is over the type's byte cap (the ~900 MB Instagram Reel is refused here, before Meta ever sees it); -- a video's duration is over the type's cap — when the duration is known. Duration is measured in the browser when you upload from the dashboard; a file attached through the REST API or a signed upload URL carries no duration, so only its size is checked. +- a video's duration is over the type's cap. Duration is read from the file's MP4/MOV header on the server when it is stored — dashboard upload, `POST /posts/{post}/media`, signed upload URL, or a public URL — so it is known for every path. A file whose container carries no duration (a fragmented MP4) is checked by size only. Drafts are never blocked: the checks run on publish and schedule only. Media attached before this check existed may lack `size` and is not size-checked until re-attached. From bd20d3c1851831a6358dde16fbd700d308b86740 Mon Sep 17 00:00:00 2001 From: Paulo Castellano Date: Sat, 12 Sep 2026 09:31:24 -0300 Subject: [PATCH 5/5] Media compatibility example message matches the editor wording --- api-reference/endpoint/update-post.mdx | 2 +- knowledge-base/media.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api-reference/endpoint/update-post.mdx b/api-reference/endpoint/update-post.mdx index f4d624a..918d2c0 100644 --- a/api-reference/endpoint/update-post.mdx +++ b/api-reference/endpoint/update-post.mdx @@ -67,7 +67,7 @@ description: "Update a post's content, schedule, enabled platforms, or labels - On update, `meta` is **merged** into the platform's existing object. Send a key as `null` to remove it (e.g. `"title": null`). - Required-to-publish keys are enforced on this request when `status` is `scheduled` or `publishing` **and** you include a `platforms[]` array in the body (each submitted row is checked). Drafts are not checked. A missing key returns `422` on `platforms.{i}.meta.{field}` (e.g. `platforms.0.meta.channel_id`). - If you publish with only `{ "status": "publishing" }` (no `platforms[]`), this endpoint does **not** re-validate stored meta — ensure `board_id` / `privacy_level` / `channel_id` were saved earlier. The MCP `publish-post-tool` always validates stored meta before publishing. -- **Media compatibility is always re-checked** on `scheduled` / `publishing`, with or without `platforms[]`: every enabled platform's effective `content_type` is validated against the post's effective media (media kind, GIF/MOV acceptance, byte cap via `size`, and video duration read from the file on upload). A failure is `422` on `platforms.{i}.content_type`, e.g. `Reel accepts a video of up to 300 MB (yours is 900.0 MB).` — see [Media → Enforced on the server](/knowledge-base/media#enforced-on-the-server-not-just-in-the-editor). +- **Media compatibility is always re-checked** on `scheduled` / `publishing`, with or without `platforms[]`: every enabled platform's effective `content_type` is validated against the post's effective media (media kind, GIF/MOV acceptance, byte cap via `size`, and video duration read from the file on upload). A failure is `422` on `platforms.{i}.content_type`, e.g. `Video exceeds the 300 MB limit for this post type (yours is 900.0 MB).` — see [Media → Enforced on the server](/knowledge-base/media#enforced-on-the-server-not-just-in-the-editor). - Enum-like fields are **JSON strings** — send the exact literal (e.g. `"privacy_level": "PUBLIC_TO_EVERYONE"`), not an integer or a different casing. - Platforms with **no** `meta` keys: X, YouTube, Threads, Bluesky, Mastodon, Telegram. diff --git a/knowledge-base/media.mdx b/knowledge-base/media.mdx index 670da2b..7741cf0 100644 --- a/knowledge-base/media.mdx +++ b/knowledge-base/media.mdx @@ -248,7 +248,7 @@ Any S3-compatible service (MinIO, DigitalOcean Spaces, Backblaze B2) works under `instagram_feed` keeps video at **100 MB / 60 seconds**. That is TryPost's conservative rule (the same as Stories), not a Meta figure — Meta only documents the Reel spec, and a single feed video is published through the Reels container anyway. Switch the content type to **Reel** (`instagram_reel`) for anything longer: up to 300 MB / 15 minutes. - Upload checks the Cloud hard cap only; publish and schedule check the per-`content_type` cap and format rules (see [Enforced on the server](#enforced-on-the-server-not-just-in-the-editor)). The response is a `422` with the message under `errors["platforms..content_type"]`, e.g. `Reel accepts a video of up to 300 MB (yours is 900.0 MB).` Fix the file, or change the platform's `content_type`, then publish again. + Upload checks the Cloud hard cap only; publish and schedule check the per-`content_type` cap and format rules (see [Enforced on the server](#enforced-on-the-server-not-just-in-the-editor)). The response is a `422` with the message under `errors["platforms..content_type"]`, e.g. `Video exceeds the 300 MB limit for this post type (yours is 900.0 MB).` Fix the file, or change the platform's `content_type`, then publish again. TryPost sends Telegram photos and videos as a **URL**, and Telegram's URL path is 5 MB (photo) / 20 MB (video). Multipart upload would allow 10 / 50 MB — that is not the path we use.