Skip to content
ShapelessAI← Back
Publishing

Platforms

Every platform the rail publishes to, with the character limit, media rules, first-comment support and per-platform settings we enforce before a post goes out.

Verified
View as Markdown

These are the rules our publishing engine enforces before a post is accepted onto the queue, so a post that breaks one is a 422 at creation rather than a failure hours later.

Read them live from GET /api/platforms - no auth, no key:

curl -s https://shapelessai.com/api/platforms
{
  "platforms": [
    {
      "id": "linkedin",
      "label": "LinkedIn",
      "oauth": true,          // connectable through the platform's own sign-in today
      "live": true,           // publishing works end to end; false = built, waiting on the platform
      "waitingOn": null,      // why it is not live, when it is not
      "text": { "maxChars": 3000 },
      "media": {
        "maxChars": 3000, "maxImages": 20, "minImages": 0,
        "allowsPdf": true, "maxVideos": 1, "requiresVideo": false, "imagesOrVideoOnly": true
      },
      "titleRequired": false, // true = documentTitle is required (YouTube)
      "firstComment": { "supported": true, "maxChars": 1250 },
      "settingsSchema": { "type": "object", "properties": {}, "additionalProperties": false },
      "connectPath": "/studio/accounts",
      "analytics": {          // what GET /api/metrics reads back for a published post
        "support": "live",    // live | pending (not readable by us yet) | locked (the platform reports nothing)
        "metrics": ["Impressions", "Reactions", "Comments", "Shares", "Members reached"],
        "note": null
      }
    }
  ]
}

settingsSchema is plain JSON Schema, which is what every MCP host and OpenAPI reader already speaks - so an agent can fill settings from it instead of hard-coding field names.

The table below is generated from the same engine table that route reads, at build time, so the two cannot drift.

PlatformidTextImagesVideoPDFFirst commentImages + videoAnalytics
LinkedInlinkedin3,000 characters201yes1,250 charsnoimpressions, reactions, comments, shares, members reached
LinkedIn Pagelinkedin_page3,000 characters201yes1,250 charsnoimpressions, reactions, comments, shares, clicks
Xx280 weighted chars41no280 charsnoimpressions, reactions, comments, shares, bookmarks, quotes
Instagraminstagram2,200 characters10 (at least 1)1nononoimpressions, reactions, comments, shares, accounts reached, saves
TikToktiktok2,200 charactersnone1, requirednonon/aviews, likes, comments, shares
YouTubeyoutube5,000 charactersnone1, requirednonon/aviews, likes, comments
Facebook Pagefacebook_page63,206 characters101nononoimpressions, reactions, comments, shares, clicks
Threadsthreads500 characters11nononoimpressions, reactions, comments, shares, quotes, sends
Blueskybluesky300 graphemes41no300 charsnoreactions, comments, shares, quotes
Reddit (waiting on Reddit's app approval)reddit40,000 characters11nonononot yet
Mastodonmastodon500 characters4not yetnonon/areactions, comments, shares
Telegramtelegram4,096 characters (1,024 with media)1010yesnoyesnone (the platform reports nothing)
Discorddiscord2,000 characters1010yesnoyesnone (the platform reports nothing)
Pinterestpinterest800 characters5 (at least 1)1nonononot yet

Reddit: Built - waiting on Reddit's app approval before we switch it on. Pinterest: Pinterest is still reviewing our app for standard access. Until they approve it, connecting works but the pins we publish may be limited - visible only to you rather than to your followers.

Counting. X counts weighted characters (a URL always costs 23, most emoji cost 2) using the official twitter-text rules. Bluesky counts grapheme clusters. Everything else counts Unicode code points. The free character counters run exactly these rules in the browser.

Images or video. Most platforms take images or a video in one post, never both. Sending both is a 422 before the row exists.

What we deliver vs what the platform allows. A few numbers above are ours, not the network's, because our adapter delivers less than the platform would take: Threads publishes one image where Threads itself allows a 20-item carousel, and Reddit one image where a gallery allows 20. The per-platform pages under /specs carry each number's source and the date we last checked it.

Reddit is waiting on Reddit's app approval. The publisher is built and the rules above are enforced, but posting to Reddit is not open yet.

Telegram posts through the Shapeless bot to one channel or group, Discord through one channel's webhook: the connection is the destination. With media attached, Telegram's text becomes a caption capped at 1,024 characters.

Settings, per platform

settings on POST /api/posts is passed through to the adapter, and settingsSchema is its JSON Schema. Today: TikTok requires an explicit privacyLevel (and takes seven more toggles), YouTube takes privacyStatus, Reddit takes one subreddit plus an optional title and url, Pinterest requires a board (by name) and takes an optional title and link, and nothing else takes settings. The shapes are on Posts.

YouTube is the one platform with titleRequired: true: its video title rides documentTitle on the post, not settings.

Connecting an account

Platform OAuth is a browser redirect carrying a platform grant, so it is deliberately the one thing an API key cannot do. Send the human to shapelessai.com/studio/accounts - connectPath in the payload above - and read the result back with GET /api/connections.

Analytics

The Analytics column above is analytics in the payload: the per-post counts we read back from each platform, in the platform's own words (TikTok says Views and Likes). They arrive on a published post as metrics from GET /api/posts and GET /api/metrics; follower counts come from GET /api/metrics/followers.

Some platforms put those numbers behind their own permission, so a connection made before we were approved for it can publish but not read. GET /api/connections says which one is which: readsMetrics: false with analyticsScopeRequestable: true means reconnecting the account once, on Accounts, turns its analytics on. TikTok joined this list on 2026-10-21, when TikTok approved user.info.profile, user.info.stats and video.list for our app: a TikTok connection made since then reads views, likes, comments and shares per video, the follower count, and the bio and recent videos that the profile audit grades.