How to post to Threads via API: Meta's publishing API for developers

A developer's guide to the Threads API — access tiers, content types, reply chains, rate limits, and how to publish to Threads programmatically without managing the OAuth complexity yourself.

How to post to Threads via API: Meta's publishing API for developers

What the Threads API actually is

Meta launched the Threads API in late 2024, giving developers programmatic access to publish, reply, and pull analytics from Threads accounts. Unlike the early months of the platform, when no API existed, developers can now automate content publishing, build scheduling tools, and create cross-posting workflows that include Threads alongside Instagram, Facebook, and other networks.

The Threads API is separate from the main Graph API. It uses a different base URL (https://graph.threads.net/v1.0/) and a different permission set than Instagram or Facebook, even though it uses the same Meta developer platform and the same OAuth infrastructure.

This guide covers what you actually need to know as a developer: access requirements, content types, how reply chains work, rate limits, and what “pricing” looks like for API access.


Access requirements and app review

The Threads API is not open by default. Before you can publish to production accounts, your app needs two things:

Tech Provider Verification — Meta requires you to verify your identity as a technology provider. This is a separate step from standard Meta developer registration. The process typically takes about a week.

Permission-level app review — Each permission requires its own app review submission, including a screencast demonstrating the exact user flow in your application. The permissions you need for publishing and analytics are:

  • threads_basic — required for all Threads API calls
  • threads_content_publish — create and publish posts
  • threads_manage_insights — read post-level and account-level metrics
  • threads_manage_replies — reply to posts and manage reply threads

Meta’s review timeline is 2–4 weeks per permission, and each screencast needs to show the complete user journey for that specific permission — not just that your app calls the endpoint, but how users interact with the feature.

While waiting for app review approval, you can publish to your own account and any accounts registered as testers in your Meta developer app. This is enough to develop and test your full integration.


Authentication

Threads uses OAuth 2.0 with short-lived and long-lived user access tokens. The flow is the same as Instagram:

  1. Direct the user to the Meta OAuth dialog with your client_id, redirect_uri, and the Threads permission scopes
  2. Receive a short-lived access token via redirect after the user authorizes
  3. Exchange it for a long-lived token (valid 60 days) using the token exchange endpoint
  4. Refresh the long-lived token before it expires to maintain continuous access
Terminal window
# Exchange short-lived token for long-lived token
curl -X GET "https://graph.threads.net/access_token?grant_type=th_exchange_token&client_secret=YOUR_SECRET&access_token=SHORT_LIVED_TOKEN"

Long-lived tokens expire in 60 days but can be refreshed at any point within that window. If you miss the window, the user needs to re-authenticate.


Publishing content: the container model

Threads uses a two-step container model for all content types:

  1. Create a container — POST to /{user-id}/threads with your content and media
  2. Publish the container — POST to /{user-id}/threads_publish with the container ID

Wait at least 30 seconds between creating and publishing, especially for video — Meta processes media asynchronously after container creation.

Text posts

Terminal window
# Step 1: Create container
curl -X POST "https://graph.threads.net/v1.0/{user-id}/threads" \
-d "media_type=TEXT" \
-d "text=Your post content here" \
-d "access_token=USER_ACCESS_TOKEN"
# Step 2: Publish
curl -X POST "https://graph.threads.net/v1.0/{user-id}/threads_publish" \
-d "creation_id=CONTAINER_ID" \
-d "access_token=USER_ACCESS_TOKEN"

Text posts are limited to 500 characters. URLs and emojis count toward this limit at their UTF-8 byte length.

Image and video posts

Terminal window
# Image post container
curl -X POST "https://graph.threads.net/v1.0/{user-id}/threads" \
-d "media_type=IMAGE" \
-d "image_url=https://example.com/photo.jpg" \
-d "text=Caption text" \
-d "access_token=USER_ACCESS_TOKEN"

For video, replace media_type=IMAGE with media_type=VIDEO and image_url with video_url. Media must be hosted at a publicly accessible URL — Meta fetches it directly during container creation.

Image specs: JPEG or PNG, max 8 MB, 320–1440px wide, aspect ratio up to 10:1, sRGB color space.

Video specs: MP4 or MOV, H264/HEVC codec, 23–60 FPS, max 1920px wide, max 5 minutes, max 1 GB. Audio: AAC, up to 48 kHz, mono or stereo.


Reply chains: how threaded replies work

This is where Threads differs meaningfully from Instagram. The platform is built around conversation threads, and the API exposes this with a reply_to_id parameter.

To create a reply to an existing post, pass the parent post’s ID when creating the container:

Terminal window
curl -X POST "https://graph.threads.net/v1.0/{user-id}/threads" \
-d "media_type=TEXT" \
-d "text=This is a reply to the original post" \
-d "reply_to_id=ORIGINAL_POST_ID" \
-d "access_token=USER_ACCESS_TOKEN"

Publish the container the same way — POST to threads_publish with the creation_id.

For multi-post threads (the Threads equivalent of a Twitter thread), you create each reply in sequence, passing the previous post’s ID as reply_to_id. There is no native “thread” object — you chain posts by reply.

You can also control who can reply to your posts using the reply_control parameter:

Terminal window
-d "reply_control=mentioned_only" # Only mentioned accounts
-d "reply_control=followers" # Followers only
-d "reply_control=everyone" # Default, everyone can reply

Carousels

Carousels support 2–20 items (images and/or videos mixed). The flow is three steps instead of two:

Terminal window
# Step 1: Create item containers (repeat for each item)
curl -X POST "https://graph.threads.net/v1.0/{user-id}/threads" \
-d "media_type=IMAGE" \
-d "image_url=https://example.com/slide1.jpg" \
-d "is_carousel_item=true" \
-d "access_token=USER_ACCESS_TOKEN"
# Step 2: Create carousel container
curl -X POST "https://graph.threads.net/v1.0/{user-id}/threads" \
-d "media_type=CAROUSEL" \
-d "children=ITEM_1_ID,ITEM_2_ID,ITEM_3_ID" \
-d "text=Carousel caption" \
-d "access_token=USER_ACCESS_TOKEN"
# Step 3: Publish
curl -X POST "https://graph.threads.net/v1.0/{user-id}/threads_publish" \
-d "creation_id=CAROUSEL_CONTAINER_ID" \
-d "access_token=USER_ACCESS_TOKEN"

Carousels count as a single post against the rate limit.


Rate limits

Threads profiles are limited to 250 posts per 24-hour period. This is per profile — if you are managing multiple Threads accounts, each has its own limit.

There is no API-level rate limit tier like X’s. The 250 posts/day cap applies regardless of which API you use to publish.

Carousels, text posts, and image posts all count equally toward this limit. Replies do not count against the 250 posts/day limit — only new posts.


API pricing

The Threads API itself is free. Meta does not charge for API access to Threads. What you pay for, if anything, is:

  • The infrastructure you build on top of it (your servers, your queue, your token storage)
  • Third-party services that abstract the API for you
  • Developer time to complete the app review process and maintain the integration as the API evolves

The cost is really the complexity: OAuth token lifecycle management, the container model’s two-step flow, app review overhead, and the ongoing work of keeping integrations current as Meta updates the API.


Linking to n8n workflows

If you are building automation workflows rather than a custom application, the Threads API integrates with n8n through Postproxy’s n8n node. The n8n social media automation guide covers the full setup, but the short version: n8n’s Postproxy node lets you publish to Threads as part of a larger workflow — triggered by RSS feeds, Notion database updates, Airtable rows, or any other n8n trigger — without writing any code.

The n8n threads api integration use case is exactly this: you want Threads posts to be one output of a larger content pipeline, not the entire application you are building.


Publishing to Threads through Postproxy

If you are building an application that publishes to Threads alongside other platforms, Postproxy handles the container model, token refresh, and app review complexity. One request publishes to Threads (and any other platform you include):

Terminal window
curl -X POST "https://api.postproxy.dev/api/posts" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"post": {
"body": "New post content"
},
"profiles": ["threads", "instagram", "linkedin"],
"media": ["https://your-cdn.com/image.jpg"]
}'

To publish a reply chain using Postproxy, include the reply_to_id in the platform-specific parameters:

Terminal window
curl -X POST "https://api.postproxy.dev/api/posts" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"post": {
"body": "Second post in the thread"
},
"profiles": ["threads"],
"platforms": {
"threads": {
"reply_to_id": "THREADS_POST_ID"
}
}
}'

Postproxy maintains approved permissions across all platforms, handles the container creation and publishing lifecycle, and delivers per-platform status so you know whether the Threads post succeeded independently from other platforms in the same request.

See the Threads API integration guide for the full technical reference on media specs, carousel publishing, and permission requirements.

Connect your Threads account and start publishing through the Postproxy API.

Ready to get started?

Start with our free plan and scale as your needs grow. No credit card required.