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.
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 callsthreads_content_publish— create and publish poststhreads_manage_insights— read post-level and account-level metricsthreads_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:
- Direct the user to the Meta OAuth dialog with your
client_id,redirect_uri, and the Threads permission scopes - Receive a short-lived access token via redirect after the user authorizes
- Exchange it for a long-lived token (valid 60 days) using the token exchange endpoint
- Refresh the long-lived token before it expires to maintain continuous access
# Exchange short-lived token for long-lived tokencurl -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:
- Create a container — POST to
/{user-id}/threadswith your content and media - Publish the container — POST to
/{user-id}/threads_publishwith the container ID
Wait at least 30 seconds between creating and publishing, especially for video — Meta processes media asynchronously after container creation.
Text posts
# Step 1: Create containercurl -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: Publishcurl -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
# Image post containercurl -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:
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:
-d "reply_control=mentioned_only" # Only mentioned accounts-d "reply_control=followers" # Followers only-d "reply_control=everyone" # Default, everyone can replyCarousels
Carousels support 2–20 items (images and/or videos mixed). The flow is three steps instead of two:
# 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 containercurl -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: Publishcurl -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):
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:
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.
Postproxy
One API for every social platform
Publish to Instagram, X, LinkedIn, TikTok, YouTube and more with a single request. Free plan, no credit card required.