Every social platform has a handful of API behaviours that are not in the quickstart. You meet them in production, usually at the worst moment, and the error message rarely tells you what is actually wrong.
These are the ones that cost us the most time building a multi-network publishing API. All of them are things we hit with real credentials against real accounts, not things we read.
1. TikTok rejects photos, and blames your video
Send a photo to TikTok's Content Posting API and you get:
tiktok requires a video_url
TikTok's Direct Post endpoint publishes video. Photo posts go through a separate flow (PHOTO post mode) that has its own approval. Most integrations discover this after a user has already scheduled twenty image posts.
What to do: validate media type per platform before you accept the post, not after. Our rule set is simply:
| Network | Needs |
|---|---|
| TikTok | video, always |
| YouTube | video, always |
| photo or video — never text-only | |
| LinkedIn, X, Bluesky, Mastodon, Telegram | text alone is fine |
2. privacy_level: "public" is not a thing
This one produces the most misleading error in the entire category:
privacy_level 'public' is not allowed for this creator
Read that as a user. It sounds like their account is restricted. It is not. The enum TikTok expects is:
PUBLIC_TO_EVERYONE
MUTUAL_FOLLOW_FRIENDS
FOLLOWER_OF_CREATOR
SELF_ONLY
public simply is not a value. The API told the truth and communicated the opposite of it.
There is a second trap behind it: an app that has not passed TikTok's audit can only post SELF_ONLY, no matter what the creator's own privacy options are. So during development every post is private, and the day your audit clears, the behaviour changes underneath you.
What to do: translate the obvious words (public, private, friends) into the platform enum, and when a level genuinely is not allowed, say why in your own error.
3. Access tokens die on very different clocks
Measured on live connections, not from the docs:
| Network | Access token lifetime |
|---|---|
| TikTok | ~24 hours |
| YouTube (Google OAuth) | 1 hour |
| Meta Page tokens | long-lived — until the user changes their password |
Every one of them refreshes silently if you built for it, and dies silently if you did not. The failure mode is nasty: your UI shows a green "Connected" badge for an account that stopped working three days ago, and the user only finds out when a scheduled post does not appear.
What to do: a status badge should be a question you asked just now, not a row you wrote once. Health-check the credential and say plainly when it needs reconnecting.
4. OAuth state cannot be raw base64
We spent a day on connections that failed only sometimes. The cause: we packed encrypted OAuth state as standard base64, which contains +, / and =. Those get URL-encoded — and in some redirect chains, double-encoded — so the callback could not decrypt what came back.
What to do: base64url for anything that travels in a query parameter. Node has it built in:
Buffer.concat([iv, tag, data]).toString("base64url");
5. Meta needs a Page, not a profile
Instagram publishing through the Graph API requires an Instagram Business account linked to a Facebook Page, and your app needs business_management to see the Page list. A personal Instagram account cannot be published to at all, and the error you get is about permissions rather than about account type — so people go hunting through their app review instead of their Instagram settings.
6. The approvals are the real work
The code for posting to any of these is an afternoon. The paperwork is not:
- TikTok Content Posting API: rejected twice for us — once for an "Invalid Website URL" — approved seven days after the second fix.
- Meta app review: seven permissions, approved clean on the first submission, but the Data Use Checkup is a separate recurring task.
- Reddit: self-serve app creation for this use case is effectively gone; it is a Data Access Request and a wait.
If you are choosing between building this yourself and using something that already has the approvals, that list is the actual decision — not the HTTP calls.
I write these down as we hit them while building PostWire, a publishing API and MCP server for TikTok, Instagram, YouTube, LinkedIn, X, Bluesky, Mastodon, Telegram, Discord and Reddit. If you have hit one that is not on this list, I would genuinely like to hear it — the undocumented ones are the expensive ones.
Top comments (0)