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"
    }
  ]
}

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 + video
LinkedInlinkedin3,000 characters201yes1,250 charsno
LinkedIn Pagelinkedin_page3,000 characters201yes1,250 charsno
Xx280 weighted chars41no280 charsno
Instagraminstagram2,200 characters10 (at least 1)1nonono
TikToktiktok2,200 charactersnone1, requirednonon/a
YouTubeyoutube5,000 charactersnone1, requirednonon/a
Facebook Pagefacebook_page63,206 characters101nonono
Threadsthreads500 characters11nonono
Blueskybluesky300 graphemes4not yetno300 charsn/a
Reddit (waiting on Reddit's app approval)reddit40,000 characters11nonono

Reddit: Built - waiting on Reddit's app approval before we switch it on.

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, Reddit one image where a gallery allows 20, and Bluesky video needs a service-auth flow we have not built. 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.

Mastodon is not offered.

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, 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.