Skip to content
Schedule Social Media

Press Esc to close.

Threads API publishing: access, permissions, limits, steps

Threads API publishing from Meta's sample code: the app and permissions, the container then publish flow, the 250-post daily quota and what's known on price.

The Threads API publishes a post in two calls: create a media container with POST /me/threads, then publish it with POST /me/threads_publish. You need a Meta app with the Threads use case and a Threads user token with threads_basic and threads_content_publish, and Meta's sample collection shows a quota of 250 posts and 1,000 replies per 24 hours.

This guide is part of Meta API use cases: which one your app needs. It is built only from Meta's official GitHub repositories (the Threads sample app, its Postman collection and the webhooks sample) and the Threads entries in our API changelog. If you want to schedule Threads posts with a tool rather than build one, read Can you schedule posts on Threads? instead.

What this means for you

Tools that post to Threads for you use this API. It can post text, images, videos, carousels, replies and quotes, but it has no "publish later" setting, so the tool keeps your post and sends it at the time you picked.

Each Threads profile also has a daily quota. Meta's example shows 250 posts a day, so a tool that posts a lot for one profile can run into it.

The details: how Threads API publishing works

Access: an app with the Threads use case

Step 1 in Meta's Postman collection is to "create a Meta app with the Threads use case". The API opened to all developers on June 18, 2024, and since September 23, 2025 it also works for profiles without a linked Instagram account.

The Threads part of the app has its own credentials. Meta's sample app README says to use the app ID and secret "defined for the Threads API of your app", which "ARE not the same as the regular app ID and app secret". The collection says where they are: App Dashboard > App settings > Basic > Threads App ID and Threads App secret.

Two rules from the same README apply to redirect URIs:

  • Add your redirect URL to the app's redirect callback URLs in the app dashboard.
  • Threads apps "do not support redirect URLs with using localhost", and "OAuth redirects are only supported over HTTPS". The sample maps a local domain in /etc/hosts and creates a certificate for it.

Meta's Threads sources on GitHub don't describe testers or App Review for Threads permissions. The only access level they mention is for embeds: with standard access, the oEmbed request can embed posts from the @meta, @threads, @instagram and @facebook accounts. Meta App Review requirements covers what Meta's samples say about roles and Advanced Access in general. Check each Threads permission's status in the App Dashboard before people outside your team connect.

Threads API permissions

Meta's sample app asks for ten permissions at login, and the collection's scope variable lists the same ten:

PermissionIn the collection's list of permissions to check on a token
threads_basicYes
threads_content_publishYes
threads_read_repliesYes
threads_manage_repliesYes
threads_manage_insightsYes
threads_keyword_searchNo
threads_manage_mentionsNo
threads_deleteNo
threads_location_taggingNo
threads_profile_discoveryNo

The collection also notes that threads_basic is enough to exchange or refresh a token. One permission from our changelog isn't in the sample's list: sharing a post to an Instagram Story needs threads_share_to_instagram.

Tokens: code, short-lived, long-lived

The sample app and the collection follow the same sequence:

  1. Send the user to {authorization_host}/oauth/authorize with client_id, redirect_uri, scope (comma-separated) and response_type=code.
  2. Exchange the code with POST {api_host}/oauth/access_token, sending client_id, client_secret, grant_type=authorization_code, redirect_uri and code. The redirect URI "must be the same URI or the request will be rejected". This returns a short-lived token.
  3. Swap it for a long-lived token with GET {api_host}/access_token?grant_type=th_exchange_token&client_secret=....
  4. Refresh a long-lived token before it expires with GET {api_host}/refresh_access_token?grant_type=th_refresh_token.

The collection's example response for the long-lived token shows expires_in of 5,184,000 seconds, which is 60 days. That is an example, not a stated lifetime, so store the expires_in your app receives. Meta access tokens compares the Threads token with Meta's other token types.

The host: graph.threads.net or graph.threads.com

Meta's own sources disagree here. Our changelog entry records graph.threads.net with v1.0 from June 7, 2024. On March 23, 2026, commit 583bfaa, titled "threads.net -> threads.com", moved the sample app to graph.threads.com for API calls and www.threads.com for authorization. The Postman collection, updated the same day, still sets api_host to graph.threads.net and authorization_host to www.threads.net.

The examples below use {api_host} for that reason. Keep the host in config so you can change it without a release. The sample app adds an optional version segment, with v1.0 as the commented-out example, and otherwise uses the app's default version.

Publish a Threads post: container, then publish

# 1. Create a container
POST {api_host}/me/threads?media_type=TEXT&text=Hello&access_token={token}
→ { "id": "{container_id}" }

# 2. Check its status (repeat until FINISHED)
GET {api_host}/{container_id}?fields=id,status,error_message&access_token={token}

# 3. Publish it
POST {api_host}/me/threads_publish?creation_id={container_id}&access_token={token}
→ { "id": "{threads_media_id}" }

media_type is TEXT, IMAGE (with image_url), VIDEO (with video_url) or CAROUSEL. Images and videos are fetched from the URL you pass ("We will cURL your image using the URL provided"), so they must be on a public server. Both take alt_text.

The status check returns one of five values, as Meta's collection defines them:

StatusMeaning
IN_PROGRESSThe container is still in the publishing process
FINISHEDThe container and its media are ready to publish
PUBLISHEDThe container's media has been published
ERRORThe container failed to complete the publishing process
EXPIREDThe container was not published within 24 hours

Meta's sample app checks the status every 5 seconds while it reads IN_PROGRESS, enables publishing at FINISHED, and shows error_message on ERROR.

Text posts in one call: auto_publish_text

A text post can skip step 3. With auto_publish_text=true, the collection says, the post "is published automatically when a Threads media container is created". The sample app sends the flag only for TEXT posts and treats the returned ID as the published post's ID, not a container ID.

Other options on the create call, from the collection:

  • link_attachment: text posts only, and not together with a poll. Without it, the first URL in the text becomes the link preview. Posts with more than five links fail since December 22, 2025.
  • poll_attachment: up to four options (option_a to option_d), text posts only, and not together with a link.
  • topic_tag, location_id, text_entities (spoilers) and is_spoiler_media.
  • reply_control: everyone, accounts_you_follow, mentioned_only, parent_post_author_only or followers_only.
  • enable_reply_approvals, added with reply approvals.
  • is_ghost_post: a ghost post "will expire after 24 hours".
  • gif_attachment. The collection's example still names TENOR as the provider, but our changelog records that Tenor was sunset by March 31, 2026 in favour of GIPHY.

Carousels

A carousel takes three calls:

  1. Create an item container for each image or video with is_carousel_item=true.
  2. Create the carousel container with media_type=CAROUSEL and children set to a comma-separated list of the item IDs. Text is optional.
  3. Publish it with threads_publish, as above.

The collection's request says a carousel holds "at least 2 and up to 20" items, which matches our September 19, 2024 entry. The saved example response under the same request still says "up to 10", so the 10 is an older figure that wasn't updated. CAROUSEL can't be used for a single post.

Replies, quotes and reposts

  • Reply: create a container with reply_to_id set to the post or reply you're answering, then publish it.
  • Quote: create a TEXT container with quote_post_id, then publish it.
  • Repost: POST {api_host}/{thread_id}/repost, one call.

Replies count against their own quota, below.

Threads API limits

GET {api_host}/me/threads_publishing_limit reports a profile's usage and limits. The fields Meta's collection asks for are quota_usage, config, reply_quota_usage, reply_config, delete_quota_usage, delete_config, location_search_quota_usage and location_search_config. Each config holds quota_total and quota_duration.

LimitWhat Meta's GitHub shows
Postsquota_total 250, quota_duration 86,400 seconds (example response)
Repliesquota_total 1,000, quota_duration 86,400 seconds (example response)
DeletionsA quota exists; no figure in the example (added July 14, 2025)
Location searchA quota exists; no figure in the example (same entry)
Unpublished containerExpires after 24 hours
Carousel2 to 20 items
Links per postUp to 5 (our changelog)

The 250 and 1,000 come from the collection's example response, not from a written rule, so read the live values before a bulk job and plan around quota_usage. For the Graph API's app-level rate limits, see Meta Graph API rate limits.

Scheduling posts with the Threads API

None of the requests in Meta's Postman collection takes a publish time, and the sample app has no scheduling code. A Threads scheduler therefore stores the post itself and runs the create and publish calls at the chosen time. Because a container expires after 24 hours, create it near the publish time, not when the user saves the post.

Webhooks

Meta's webhooks sample sets up Threads webhooks "as a sub use case under the Threads API main use case", with a callback URL that answers the hub.mode, hub.verify_token and hub.challenge check. Threads webhooks launched on August 13, 2024, and the changelog later added mention, delete and publish webhooks. Meta webhooks covers verification and signatures for all three Meta networks.

Threads API pricing: what Meta's sources show

No price, paid tier or usage charge appears in Meta's Threads sample app, its Postman collection or the Threads entries in our changelog. We don't call the API free, because none of those sources says so either. What they do show is the quota system above: limits per profile, reported by threads_publishing_limit.

What changed in the Threads API, by date

DateChange
2024-06-18Opens to all developers
2024-08-13Webhooks
2024-09-19Carousels up to 20 items
2025-03-06Post deletion, then polls on April 14
2025-07-14Quotas for deletions and location search
2025-09-23Profiles without Instagram
2025-11-20Profile discovery from 100 followers
2025-12-22More than five links rejected
2026-03-23Meta's sample app moves to graph.threads.com (commit 583bfaa)
2026-03-25Reply approvals and sharing to an Instagram Story
2026-03-31Tenor GIFs sunset; GIPHY instead

What to do next

  • Business owners: You don't need to build anything. If a tool posts to Threads for you, it works within a daily quota per profile, and the Threads hub lists the tools that publish there.
  • Marketers and agencies: If one profile gets a lot of posts and replies through a tool, ask how the tool handles the quota and what happens to a post that fails at its scheduled time.
  • Developers: Create the app with the Threads use case, request only the permissions you use, keep the API host in config, poll the container until FINISHED before publishing, and read threads_publishing_limit before bulk jobs.

Questions people ask

How much does the Threads API cost?

We can't state a price. No price, paid tier or usage charge appears in Meta's Threads sample app or Postman collection on GitHub, or in the Threads entries in our API changelog. What those sources do show are quotas: a profile's posts, replies, deletions and location searches are counted against limits that the threads_publishing_limit request reports.

How many posts can the Threads API publish per day?

The example response in Meta's Postman collection shows a quota of 250 posts and 1,000 replies, each with a duration of 86,400 seconds (24 hours). That is an example response, so read the real figures for each profile from GET /me/threads_publishing_limit before a bulk run.

Can you schedule a post with the Threads API?

Not with a publish time. None of the requests in Meta's Postman collection take a scheduled time, so your app stores the post and makes the create and publish calls when the time comes. An unpublished container expires after 24 hours, so create it close to the publish time.

Which permissions does the Threads API need to publish?

Meta's collection names threads_basic and threads_content_publish among the permissions to check on a token, and its sample app requests both at login, along with eight more for replies, insights, search, mentions, deletion, location tagging and profile discovery. Ask for the ones your features use.

Do I need an Instagram account to use the Threads API?

No. Since September 23, 2025 the Threads API works for Threads profiles without a linked Instagram account. Two metrics, followers_count and follower_demographics, were left out at first and became available to those profiles on January 30, 2026.

Sources

Related

Get an email when a platform changes its API

One email per new entry: what changed, who is affected, and the deadline.

Follow with RSS, or per platform, for example X or Meta.