Why your integration reports success when nothing published

A failed API call is easy. It returns an error, you read it, you fix it. The expensive failures are the ones that return 200 OK and leave nothing on the account — because there is no error to read, no alert to fire, and no way to tell without going and looking.

These are the four that matter for TikTok, Instagram and YouTube. I know them well: I shipped all four, and only found them by auditing the database months later.

Written for developers and AI-agent builders publishing on behalf of users. September 2026 — platform behaviour changes, so confirm against the official docs.

What your code sees compared with what the platform is doing Two timelines. Your code posts, gets a 200 response and stops watching after a few seconds. The platform is still transcoding for up to several minutes and only then decides whether the post is published or rejected. What your code sees POST /publish 200 OK marked published nobody is watching here What the platform is doing upload accepted transcoding — seconds to minutes PUBLISH_COMPLETE or FAILED
The response tells you the upload was accepted. It does not tell you the post survived.
01

The unaudited client posts privately

TikTok

Symptom

The API returns success, the video exists on the account, and nobody but the owner can see it.

What is actually happening

Until an app passes TikTok's Content Posting audit, every post it creates is forced into private viewing mode. The privacy_level you send is overridden or rejected outright. Nothing in the success response says this happened.

How to catch it

Look for unaudited_client_can_only_post_to_private_account in the raw error body, and read back the privacy level TikTok actually applied rather than the one you asked for.

02

Publishing is asynchronous and your request is not

TikTok

Symptom

Your code returns 200 in a couple of seconds. The post shows as published in your UI. Whether it survived transcoding is unknown.

What is actually happening

video/init hands back a publish_id and returns immediately. Transcoding continues for anywhere from seconds to several minutes, and can still fail at the end. A short poll that times out and reports success is guessing.

How to catch it

Persist the publish_id the moment the upload is accepted. If you have not stored it, a post stuck mid-flight can never be resolved — the platform offers no way to look up a finished upload after the fact.

03

Every platform is media-only

All three

Symptom

A caption-only post is accepted by your own API, then fails later with an error about media URLs that does not mention the real problem.

What is actually happening

YouTube, TikTok and Instagram cannot publish text on its own. If your endpoint accepts a post with no video and no image, you have deferred a guaranteed failure to publish time, where the error message belongs to someone else.

How to catch it

Reject medialess posts at your own boundary with a message that names the actual requirement. The failure is deterministic, so there is no reason to discover it downstream.

04

Tokens do not expire the same way

TikTok vs Instagram

Symptom

One platform keeps working months after its access token expired. Another silently stops and never recovers.

What is actually happening

TikTok issues a refresh token valid for roughly a year, so an expired access token is usually recoverable without involving the user. Instagram long-lived tokens last about 60 days and must be refreshed before they lapse. Once expired there is nothing to refresh.

How to catch it

Treat expiry as per-platform, not global. Check Instagram's remaining lifetime proactively and prompt for reconnection before it lapses, rather than discovering it on the next publish.

The one-character version of trap 02

Trap 02 is worth showing in detail, because the bug that causes it looks completely correct in review. TikTok reports in-progress uploads with several distinct status values. A polling loop written against the word PROCESSING matches none of them, exits after a single check, and reports whatever the author assumed a timeout meant.

TikTok publish states and the value naive polling looks for TikTok moves an upload through PROCESSING_UPLOAD and PROCESSING_DOWNLOAD before reaching the terminal states PUBLISH_COMPLETE or FAILED. A loop condition testing for the exact string PROCESSING matches none of these values. What TikTok actually reports PROCESSING_UPLOAD PROCESSING_DOWNLOAD PUBLISH_COMPLETE FAILED terminal terminal What the loop tests for "PROCESSING" matches none of the four values above — so the loop runs once and exits, no matter how high you set maxAttempts.
A 30-attempt retry loop that never retried. The bug is invisible in review because the constant looks like the thing it is comparing to.

The failure mode compounds. Because the loop exits immediately and the timeout path is treated as success, the post is recorded as published, the platform's job identifier is discarded, and the record becomes permanently unresolvable — there is no API for asking a platform how an upload you no longer have an identifier for turned out.

What honest state looks like

The fix for all four traps is the same shape: stop treating "the request returned" as "the post exists". That means three states rather than two, and something that resolves the middle one.

A two-state model compared with a three-state model Modelling a post as only published or failed forces in-flight uploads to be misreported. Adding a pending state, with a stored job identifier and a reconciler, lets the outcome be established later. Two states — in-flight has to be a lie published failed Three states — in-flight is a fact published failed pending reconciler resolves it using the stored job id An upload still transcoding is neither of these. Forcing it into one of them is where the lie starts.

The checks worth adding today

  • ·Persist the platform's job identifier the moment an upload is accepted, before anything can go wrong.
  • ·Never let a polling timeout resolve as success. A timeout means unknown, and unknown is its own state.
  • ·Compare against the platform's real status values, not a word that resembles them. Assert on the terminal states you expect.
  • ·Reject impossible posts at your own boundary — no media means no post, on every one of these platforms.
  • ·Read back what the platform applied, not what you requested, especially privacy level while unaudited.
  • ·Count published posts, not successful requests. If those two numbers can differ, only one of them is real.

Questions people arrive with

Why does the TikTok API return success but the video is not on my profile?

Three common causes. If your app has not passed TikTok's Content Posting audit, every post is forced to private and only the account owner can see it. If your code stopped polling before TikTok finished transcoding, the upload may have been rejected after your request returned. And if you polled for a status literally equal to PROCESSING, you never matched TikTok's real in-progress values and exited after a single check.

What does PROCESSING_UPLOAD mean in the TikTok Content Posting API?

It means TikTok has accepted your upload and is still working on it. It is not a terminal state. The terminal states are PUBLISH_COMPLETE and FAILED. Code that loops while the status equals the string PROCESSING never matches PROCESSING_UPLOAD or PROCESSING_DOWNLOAD, so it stops polling immediately and reports whatever it assumed.

Why are my TikTok API posts private even though I set PUBLIC_TO_EVERYONE?

An unaudited client cannot post publicly regardless of the privacy_level you send. TikTok either rejects the value or forces the post private. Passing the Content Posting audit is the only way to lift it, and until then the API still reports success.

Can I publish a text-only post to TikTok, Instagram or YouTube?

No. All three are media-only. A post with no video and no image has nowhere to go, and depending on the platform you will get either a validation error or a misleading one about media URLs. Reject medialess posts in your own code before you accept them.

Why did my Instagram token stop working when TikTok's kept refreshing?

They expire differently. TikTok issues a refresh token valid for around a year, so an expired access token is usually recoverable without user action. Instagram long-lived tokens last about 60 days and must be refreshed before they lapse — once expired, there is nothing to refresh and the user has to reconnect.

How do I know whether a post actually published?

Only by asking the platform after the fact. Persist the platform's own job identifier — TikTok's publish_id — at the moment the upload is accepted, then reconcile it against the status endpoint on a schedule. Without that identifier stored, a post stuck mid-flight can never be resolved.

The other half of this problem is getting permission to publish at all — TikTok's Content Posting audit, Instagram's Business Verification, YouTube's OAuth verification and upload quota. That is covered in what it actually takes to get publishing API access.

QPost is the API and MCP server I build; it holds those approvals and handles the reconciliation described here, so an agent can publish without every project rediscovering these four traps.