The Business Reality8 min read

It Took Three Rejections Before I Calculated That Approval Would Have Saved Me Nothing

I got rejected twice from a short-form auto-posting API review and fixed the icon and the domain. The third rejection had nothing to fix. Only then did I do the math: even with approval, the number of human clicks I would save was zero — and that was written in the guidelines on day one.

#reality-check#first-principles#api#distribution
Left: what platform approval unlocks — private-only posting becomes public posting, and that is the whole list. Right: what it does not unlock — the sharing guidelines still demand explicit consent per post, so a human opens the form, previews, picks privacy and presses publish. Human clicks saved by approval: zero.
Approval unlocks one permission. What I actually wanted was fewer human hands.

Before entering a platform review, have you ever written down — in one sentence — exactly what changes if you get approved?

I didn't. I spent two weeks in review, collected three rejections, and only when the last one turned out to be unfixable did I finally run the math. The answer was "nothing."

What I was trying to do

The short-form pipeline was already running. It renders vertical videos from app assets and auto-publishes to three YouTube channels (ko/en/ja) every day. YouTube needs no API review, so that part was unattended a long time ago.

I wanted to bolt one more short-video platform onto it. The rendered mp4s and the publish queue would be shared with YouTube; only the published-state ledger needed to be separate. The code went through in a day. Three videos actually reached PUBLISH_COMPLETE in the sandbox. All that was left was review approval.

Rejection 1: the icon

The first rejection said my app icon didn't match the icon on my website.

It was the same artwork, so I assumed a mistake — then I opened both files and they really were different. The PNG I'd hastily made for the demo recording was a hard square with fully opaque corners (alpha 255); the actual site favicon was a rounded square with fully transparent corners (alpha 0). I had matched size and proportion and never looked at the corner alpha. It was a mismatch visible to the naked eye. The reviewer was right.

I scaled the favicon coordinates exactly to 1024px, re-rendered on a transparent background, and resubmitted. A legitimate rejection.

Rejection 2: "the website is not fully developed"

The second rejection said the registered Website URL wasn't "fully developed" — landing/login pages not accepted.

That URL was my hub with 40-odd apps on it. Not a single landing page. Digging into it, the CDN in front of the domain was serving a bot-check challenge to automated requests. Even with a browser user agent, the apex domain returns 403. What the review crawler saw was not my hub but a challenge page.

This was not the kind of thing I could fix — loosening the CDN creates other problems. So I swapped the URL to this dev blog's domain. It returns a clean 200 and has over a hundred published posts, which leaves no room to argue about "fully developed." I rebuilt the icon as well and resubmitted both.

Up to here I did well. For both rejections I found the real cause, verified it by measurement, and fixed it.

How would you read the third rejection?

The third reply came in.

TikTok for Developers currently does not support
personal or internal company use.
 
Not acceptable: A utility tool to help upload contents
to the account(s) you or your team manages.

The second sentence is the definition of my app. A utility that uploads my content to accounts I manage. That is what I built, and that is what is disallowed.

There was a fork here. The two previous rejections got fixed and resubmitted, so the hand moves reflexively — reword the submission notes, rewrite the use-case description, touch up the icon again. When the loop rejection = defect = fix has succeeded twice, that loop fires first on the third one too.

But this reason contains no defect. It isn't a surface issue like an icon or a URL; it's a ruling about the category the app belongs to. A self-posting tool is simply not who this API is for, no matter how well it meets the spec. Resubmitting the same app earns the same reason. Trying to fix an unfixable reason only buys a fourth rejection.

So I finally did the math

Only after deciding not to resubmit did I ask the question I should have asked first. What would have changed if it were approved?

I reopened my notes and the answer was already there. On day one of the work, I had written this:

The sharing guidelines require explicit user consent for every post: the privacy dropdown has no default, comment/duet/stitch are all off by default, the commercial-content toggle is off by default, music-usage disclosure appears before the publish button, a preview must be shown, no watermarks or preset captions.

Approval releases exactly one constraint — "content posted by unaudited clients is restricted to private viewing." Once that's gone, you can post publicly.

The consent requirement is not released. Even after approval, a human must open the form for every single post, look at the preview, pick the privacy level, and press publish. That's why I never wired this API into the unattended scheduler in the first place — a --yes flag would break the very consent flow that justified the approval. That's the reason the click-through approval form exists as a separate local web page.

Written out, the end state after approval looks like this:

  • A human opens the form, checks the preview, picks the privacy level, presses publish. Once per video.
  • The same number of human hands as uploading by hand in the platform's own app.

What approval would have bought is the single fact "it can be posted via API," and the human effort saved is zero. What YouTube auto-publishing gives me — zero human touches per day — this one cannot give even when approved.

The rejection did not destroy the value. It revealed that there was never any value there.

There was no denominator either

One more thing. Exposure and referral data for this channel is still zero. Everything published was the three sandbox videos, all private. Captions can't carry clickable URLs on this platform, so the only referral path is the profile link.

Which means even if I had kept chasing approval, measuring "does this channel work" would have had to start from accumulating exposure. This is the same family as setting the re-measure date without ever taking the baseline — I was chasing eligibility while the numbers needed to judge it were never prepared.

What I had to tear out: nothing

Shutdown cost was zero. Zero scheduled jobs, zero inclusion in the automated pipeline. Because I held to the rule of "no pipeline inclusion before approval," there was nothing to unschedule.

grep -ril tiktok ~/Library/LaunchAgents/   # 0 hits
grep -c -i tiktok engine/autopilot.sh      # 0

Code, credentials and the publish ledger are all preserved, with a termination banner added at the top. It's the same reason the channel I closed without ever turning it on cost nothing to abandon — if it isn't tied to anything yet, detaching it costs nothing. The plumbing already went through end to end (three real sandbox posts), so if the policy changes I can switch it back on then.

I also wrote down what I will not do: resubmit (the reason is eligibility, so it's pointless) · describe it as a multi-user product in the paperwork only (that would be lying to a reviewer) · route around it with device automation (terms violation plus account-ban risk).

Three-line self-check

If you have a track waiting on a review, an approval, or eligibility, check these three.

  1. Can you write "what changes if approved" in one sentence? If you can't, you haven't done the math yet. Tracks whose answer is "nothing" genuinely exist.
  2. Have you listed which constraints approval releases and which it does not? Usually approval releases one permission while a different clause keeps blocking the automation you actually wanted.
  3. Is the rejection reason a defect or an eligibility ruling? Defects get fixed; eligibility doesn't budge when you fix things. Processing both with the same reflex just earns more rejections.

The honest part

Fixing the icon and URL rejections wasn't waste. I found the real causes by measurement, and along the way learned that the CDN blocks automated requests — information I keep using in other automated verification.

The waste was not recalculating the value of the track while it was in progress. Work in progress does not re-examine its own worth. Once "fix the next rejection" becomes the task in front of you, the question "what do I get by passing this" disappears. The answer was in my day-one notes, and I didn't reopen those notes for two weeks.

Short-form itself keeps shipping to the three YouTube channels. The render pipeline and the queue are unaffected. What I lost is this one platform, and what it was going to give me was zero from the start.

If you're waiting on an approval right now, write down the number of human touches it will save you. If that number is zero, closing today is the profitable move.

Related