POST /{threads-user-id}/threads returns HTTP 500 with an empty body when a container request carries reply_control on a token without threads_manage_replies. Meta returns no permission error and no error object. In our production traffic the request failed in under half a second, while the identical request without reply_control succeeded. We reproduced it against a live account in September 2026, and Meta's docs checked on 18 October 2026 mention neither a 500 nor an empty response.
A parameter Meta does not document produces the identical response, so the status code cannot tell you which cause you hit. This post gives the parameter and permission table, a procedure that isolates the culprit, and the second Threads surprise: the webhook payload has no entry[] or changes[] envelope.
What does Meta document about errors on POST /{threads-user-id}/threads?
Very little: the endpoint has no documented error codes and no permissions section. Meta's publishing reference lists 24 optional and conditional parameters plus access_token for POST /{threads-user-id}/threads (checked 18 October 2026). The posts guide names no permissions either.
The troubleshooting guide documents container status errors such as FAILED_DOWNLOADING_VIDEO and INVALID_DURATION, which arrive in a status read after creation. It does not mention HTTP 500 or an empty response (checked 18 October 2026).
The one documented creation-time failure is the link limit: "Starting December 22, 2025, Threads posts containing more than 5 links will fail to post during the media creation step", with the error code THREADS_API__LINK_LIMIT_EXCEEDED (posts guide, checked 18 October 2026). That failure returns a named error. A missing permission, in our traffic, did not.
What permission does reply_control need, and what do other parameters need?
reply_control needs threads_manage_replies, which Meta describes as permission to "control who can reply to a thread on the Threads profile" (permissions reference, checked 18 October 2026). The table maps each creation parameter to the scope whose description covers it. Where the description does not mention the parameter, the cell says so rather than guessing.
| Parameter | Permission Meta ties to it | Without the permission |
|---|---|---|
reply_control | threads_manage_replies: "control who can reply to a thread on the Threads profile" (permissions reference) | Observed: HTTP 500, empty body (September 2026) |
location_id | threads_location_tagging: "publish media with a location tagged" (permissions reference) | Not tested |
enable_reply_approvals | Not stated on the reply management page or the publishing reference | Not tested |
topic_tag | None named beyond the publish scopes | Not applicable |
link_attachment | None named beyond the publish scopes | Not applicable |
quote_post_id | None named beyond the publish scopes | Not applicable |
allowlisted_country_codes | None named beyond the publish scopes | Not applicable |
poll_attachment, gif_attachment, text_attachment, text_entities | None named beyond the publish scopes | Not applicable |
is_ghost_post, is_spoiler_media, alt_text, auto_publish_text, crossreshare_to_ig, crossreshare_to_ig_dark_mode | None named beyond the publish scopes | Not applicable |
| Any key not in the publishing reference | None | Observed: HTTP 500, empty body |
"The publish scopes" means threads_basic, which "allows an app to get a user's Threads profile information and the media and text content that they posted," and threads_content_publish, which "allows a business app to create and publish content on behalf of a Threads profile" (permissions reference, checked 18 October 2026). The reference does not say these two are sufficient for every parameter in the table. It only names nothing else.
Read the "Not applicable" cells for what they are: Meta names no extra permission for those parameters, and we did not observe any of them failing for permission reasons. That is an absence of evidence in Meta's documentation, not a guarantee. The enable_reply_approvals and location_id rows stay "Not tested" because we have not run them against a token that lacks the scope.
Your token's scope list comes from the scope you sent to authorize, and a user who connects without threads_manage_replies holds a token that cannot set a reply audience. Meta's access token guide says the token response returns "the app user's short-lived access token, the token type, and User ID" and documents no endpoint that reads the granted permissions back (checked 18 October 2026). Keep your own record of which scopes each user approved.
How do you find which parameter causes the empty 500?
Strip optional parameters until the 500 stops, then add them back one at a time. The first one that brings the 500 back is the culprit. The four steps below are the whole procedure, and the diagram shows where each outcome leads.
Swipe sideways to see the whole diagram
Start from the documented minimum request, then reintroduce optional parameters one at a time. A failure of the minimum request points away from your parameters.
- 1.Log the full request parameters at the moment of failure, with the token masked. The 500 carries no body, so the request is your only evidence.
- 2.Re-send the container request with only the documented minimum:
media_type,text(orimage_urlorvideo_url), andaccess_token. If it succeeds, the cause is an optional parameter. - 3.Add the optional parameters back one at a time. Start with
reply_controlandlocation_id, the two with a named permission. - 4.Compare the culprit with Meta's list of parameters and with the scopes the user approved. A documented parameter whose scope the user never approved is the permission case. A key missing from the reference is the undocumented case.
One caution from our traffic: a bare 500 is not proof of a bad parameter or a missing scope. We have seen Threads container creation fail for a short period for requests that carried only the documented minimum, while other accounts published normally. If step 2 fails too, retry later and read the fbtrace_id header if one is present before you change your parameter set.
What does a Threads webhook payload look like?
A Threads webhook is one flat JSON object per request, with app_id, topic, target_id, time, subscription_id, has_uid_field and values at the top level. Meta's Threads webhooks page mentions neither entry nor changes (checked 18 October 2026). A handler written for the Instagram shape reads an empty list and drops every Threads event without an error.
Both blocks below are examples with placeholder values, not captured traffic. First, the Instagram and Facebook envelope, where events sit inside entry[] and changes[]:
Second, the Threads shape for a reply, shortened from Meta's replies sample (checked 18 October 2026). It drops permalink, shortcode, timestamp and media_type:
Three details matter to a handler. First, target_id changes meaning by field. Meta's Fields table defines it as "The media's ID for a reply or delete webhook, or the mentioned Threads user app-scoped user ID for a mentions webhook." For a reply the account that owns the conversation is in values.value.root_post.owner_id.
Second, topic differs by field: the replies sample uses "moderate" and the mentions sample uses "interaction". Route on values.field, not on topic. Third, the scopes differ by field: replies need threads_basic and threads_read_replies, mentions need threads_basic and threads_manage_mentions, delete needs threads_basic and threads_delete, and publish needs threads_basic (Threads webhooks page, checked 18 October 2026).
The mentions sample carries media_product_type, has_replies, is_reply and text. Meta says has_replies, is_reply, replied_to and root_post are removed without threads_read_replies.
Why am I not receiving Threads mention webhooks?
The likeliest cause is missing Advanced Access. Meta states that an app without Advanced Access on its permissions will not receive webhook notifications, and that to receive all fields the app must complete App Review for Advanced Access (checked 18 October 2026). Check the subscription scopes too: mentions need threads_basic and threads_manage_mentions.
In our traffic this showed up sharply on mentions. Before the app held Advanced Access for threads_manage_mentions, no mention webhook reached us for accounts other than the app's own testers, and a polling read returned an empty list for them. Meta's page does not mention testers, so treat that detail as a first-party observation, not documented behaviour.
For the publish flow itself (the two-step container and publish calls, the 250-posts-per-24-hours cap and carousel rules) see the Threads publishing developer guide. The signature check on the X-Hub-Signature-256 header is covered in webhook signature verification.
Questions developers ask about Threads API errors and webhooks
- Why does the Threads API return a 500 error with an empty body?
- In our production traffic (September 2026),
POST /{threads-user-id}/threadsreturned HTTP 500 with an empty body forreply_controlon a token withoutthreads_manage_replies, and for a parameter Meta does not document. Meta's docs checked 18 October 2026 mention neither. Remove optional parameters one at a time to find the cause. - What permission does reply_control need?
threads_manage_replies, which Meta's permissions reference describes as the ability to "control who can reply to a thread on the Threads profile" (checked 18 October 2026). Without it, the container request returned HTTP 500 with an empty body in our September 2026 traffic. Meta's publishing reference itself names no permission for the parameter.- Which permission does location_id need?
threads_location_tagging, described by Meta as "publish media with a location tagged" (permissions reference, checked 18 October 2026). We have not tested whatlocation_idreturns on a token without it, so do not assume it matches thereply_controlbehaviour.- What does a Threads webhook payload look like?
- A flat object with
app_id,topic,target_id,time,subscription_id,has_uid_fieldandvaluesat the top level, and noentry[]orchanges[]envelope (Meta's Threads webhooks page, checked 18 October 2026). The event itself sits invalues.value, andvalues.fieldnames the type, such asreplies. - Why am I not receiving Threads mention webhooks?
- Meta says an app without Advanced Access on its permissions will not receive webhook notifications (checked 18 October 2026), and mentions need
threads_basicandthreads_manage_mentions. In our traffic, no mention webhook arrived for non-tester accounts until the app held Advanced Access forthreads_manage_mentions. - What does target_id mean in a Threads webhook?
- It is the media id for a
replyordeletewebhook and the mentioned user's app-scoped user id for amentionswebhook (Meta's Threads webhooks page, checked 18 October 2026). For a reply, read the conversation owner fromvalues.value.root_post.owner_id.
SocialAPI.ai covers Threads through one API: see the Threads platform page. If a Meta fact on this page is wrong or has changed, tell us and it gets corrected with a date.
Every Meta claim above traces to a page on developers.facebook.com, each checked 18 October 2026. Statements labelled as observed come from our own production traffic in September 2026 and are not in Meta's documentation. Meta, Threads publishing reference, Meta, Threads posts guide, Meta, Threads troubleshooting guide, Meta, Permissions reference, Meta, Threads reply management, Meta, Threads access tokens and permissions, Meta, Threads webhooks