← All posts

What it actually took to get Threads publishing approved

Srinivasa Reddy, Founder, Zolt AI · · 6 min read

If you've tried to get a real app approved to post to Threads on someone's behalf, you've probably found the same thing we did: a handful of forum posts, Meta's own documentation scattered across two different developer surfaces, and not much of an actual account of what the process is like end to end. This is that account — what we needed, what confused us, and the two things that would have saved us the most time if we'd known them going in.

Threads is not part of your Meta app

The first thing worth knowing, because it isn't obvious from the developer console: a Threads integration is not a feature you add to an existing Facebook/Instagram app. It's a separate app, with its own App ID and secret, its own API host (graph.threads.net, not graph.facebook.com), and its own API version track — we're on Threads API v1.0 while our Meta integration runs v21.0, and those two version numbers are not related to each other at all. If your code assumes one Graph API version applies everywhere, this will find that assumption immediately, in a way that doesn't fail loudly — it fails as a confusing error from an endpoint that just doesn't recognize the version you sent it.

Practically: build a small helper that picks the API version and the host based on which platform you're calling, from day one. Retrofitting that distinction after your code already assumes "one Graph API" is more painful than it sounds, because the assumption tends to be everywhere — URL construction, error handling, pagination, all of it.

The permission that looks like one thing and is two

This is the mistake that cost us the most time, so it's worth being specific. Threads has a permission called threads_manage_replies. It sounds like it covers "handling replies" — reading them and responding to them. It doesn't. It covers writing replies only: posting a response. Reading the replies on your own post is a separate permission, threads_read_replies, requested and reviewed independently.

We initially assumed a review gate on the write permission also covered reading, built around that assumption, and only found out otherwise when a live API call for reply data came back empty with no obvious explanation. The fix was adding the fifth scope we'd been missing — but the real fix was realizing, before writing any integration code, that Meta's permissions are granular in ways their names don't always suggest. If a permission name sounds like it might bundle two capabilities, assume it doesn't, and check the documentation for each verb (read vs. write) separately before you build around either assumption.

What the screencast actually needs to show

Meta's App Review for a publishing permission requires a screen recording of your app actually using it — not a description, a real screen capture of the feature working. A few things we learned the specific way (by having a submission sent back):

  • Show the real UI a real user would see, not a bare API call in a terminal or Postman. Reviewers are checking that a genuine human, using your product normally, can reach and use the feature — not that the endpoint technically works.
  • Show the permission being requested and granted, on screen, as part of the flow — not assumed to have already happened before the recording starts.
  • One scope, one clear demonstration. If you're requesting five scopes across two apps (our case — Meta and Threads, several permissions each), don't try to compress everything into one recording. Meta reviews against a checklist per permission; a shorter, focused clip per capability is easier for a reviewer to verify than one long recording where a specific permission's usage is buried in the middle.
  • Narrate what's happening, or caption it. A reviewer with no context on your product is watching this once. If the significance of a click isn't obvious from the click alone, say what it does.

The callback almost everyone forgets

Buried in Meta's platform terms, separate from the App Review checklist most guides focus on: if your app can access someone's data, you're required to handle two specific webhook-style callbacks — a deauthorize callback, fired when a user revokes your app's access, and a data deletion request callback, which must return a status page a user can check on the deletion's progress.

Both callbacks arrive as a signed_request parameter — a base64-encoded payload with an HMAC signature you're expected to verify against your app secret before trusting anything in it. This isn't optional hardening; it's the actual authentication mechanism Meta uses for these callbacks, and skipping verification means anyone who discovers your callback URL could send you a fake deletion or deauthorization request with attacker-supplied data.

We found a real bug here worth naming honestly: our data-deletion callback verified an incoming signed request against only one of our two apps' secrets. Every deletion request for the other app would have failed signature verification and been refused — a compliance failure that a working App Review submission would not have caught, because Review checks that the endpoint exists and runs, not that it accepts every valid caller. We found it by reading the code with the specific question "does this actually work for both apps," not by any automated check. If you're running more than one Meta or Threads app under one codebase, that's the exact seam this kind of bug hides in.

What we'd do differently starting over

Treat the two APIs as fully separate systems from the first line of code — a shared helper that dispatches on version and host, not "extend the Meta client and hope." Read the documentation for a permission's read and write halves separately, and assume they're independently gated until proven otherwise. Record one focused clip per scope for review, showing the real product UI. And if you support more than one app, write the test that calls your callback with every app's real signature, not just one — because that's precisely the case a passing App Review will never check for you.

None of this is Meta being unreasonable. A platform that lets third-party apps post on someone's behalf and touch their data should ask hard questions before granting that. It's just a process with real, specific sharp edges that nobody had written down plainly when we needed it — so here it is, written down.

Curious what Zolt actually does day to day? See how it works, or go straight to pricing.