Publish, read, search, listen, and measure - the official Meta Threads API, fully documented on one page. Free to use, OAuth-secured, with code in Python, JavaScript, and PHP.
# 1 - stage the post curl -X POST "https://graph.threads.net/v1.0/$UID/threads" \ -d media_type=TEXT \ -d text="Hello, Threads 👋" \ -d access_token=$TOKEN → {"id":"18027481937261"} # 2 - go live curl -X POST "https://graph.threads.net/v1.0/$UID/threads_publish" \ -d creation_id=18027481937261 \ -d access_token=$TOKEN → published ✓
Official documentation sits on Meta for Developers - everything else on the internet is commentary.
Getting started, publishing, insights, keyword search, reply management, webhooks, oEmbed, and troubleshooting - one canonical tree.
Start at Overview → Get Started for app setup, then jump straight to the guide for your use case. Reference pages list every field and permission per endpoint.
The API ships fast - 2026 alone added ghost posts, Instagram cross-sharing, spoiler tags, text attachments, and reply approvals. The changelog page is worth a bookmark.
Meta publishes no paid tier, per-call fee, or quota-upgrade product for the Threads API.
Your real costs are engineering time and hosting. Budget for those; the API itself stays free.
Access is self-serve: no application essay, no sales call.
In the Meta for Developers dashboard, create an app and add the Threads API use case.
Add redirect URIs, invite Threads testers, and exercise endpoints with standard access on your own account.
For public users and sensitive scopes (like threads_keyword_search), complete App Review with a demo of your use case.
Move tokens to production storage, subscribe webhooks, and monitor your quota via /threads_publishing_limit.
Unlike simple key-based APIs, Threads uses OAuth access tokens that represent a specific user's permission grant.
Your app has an App ID and App Secret - these identify your software, but can't call user endpoints alone.
Each connected account grants a token scoped to specific permissions - that token is what authorizes every API call.
Environment variables and secret managers only - never in code, repos, or client-side JavaScript.
The developer experience is deliberately boring - in the best way.
Generate test tokens and fire requests from the browser before writing a line of code.
Invite teammates as testers so development never touches production accounts.
JSON in, JSON out, standard HTTP codes, cursor pagination, and field selection with ?fields= - if you've used any Graph API, you already know it.
"Meta Threads API" is the formal name - and the Meta pedigree is the point.
App dashboard, App Review, permissions model, and policy framework are shared with Facebook and Instagram APIs - one mental model across Meta.
Meta Platform Terms apply: respect user data, request minimal scopes, and pass review for public access.
Meta ships Threads API features fast - the 2026 wave (ghost posts, cross-sharing, reply approvals, webhooks) signals long-term platform investment.
Threads accounts are built on Instagram identity - and the API reflects it.
Accounts authenticate via their Instagram login; usernames stay in sync across both apps.
The 2026 threads_share_to_instagram scope enables crossreshare_to_ig parameters on publish - one API call, two surfaces.
The Instagram Graph API and Threads API are separate products with separate tokens and scopes - related family, different doors.
Threads follows Graph API conventions on its own host: graph.threads.net.
# Base URL - note: threads.net, not facebook.com https://graph.threads.net/v1.0/... # Field selection GET /me?fields=id,username,threads_profile_picture_url # Cursor pagination GET /me/threads?limit=25&after={cursor} # Versioned paths - pin your version, watch deprecations GET /v1.0/{user_id}/threads
Every post - text, image, video, carousel, GIF, or ghost post - goes container-first, then publish.
# Step 1 - create the media container POST /v1.0/{user_id}/threads ?media_type=TEXT &text=Hello+Threads+👋 &access_token={token} → {"id": "18027..."} # creation_id # Step 2 - publish it POST /v1.0/{user_id}/threads_publish ?creation_id=18027... &access_token={token} → {"id": "18027..."} # live post ID ✓ # Media: media_type=IMAGE|VIDEO|CAROUSEL + image_url/video_url # 2026 extras: ghost posts, spoiler tags, crossreshare_to_ig
"Analytics API" in practice means the insights endpoints plus your own storage and charts.
The API returns current values; historical trendlines are yours to build by snapshotting on a schedule. Data availability starts from April 2024.
Two levels: per-post media insights and account-level user insights.
| Level | Metrics | Notes |
|---|---|---|
| Post (media) | views, likes, replies, reposts, quotes, shares | GET /{media_id}/insights?metric=… |
| Account (user) | views, likes, replies, reposts, quotes, followers_count, follower_demographics | Demographics need a minimum follower threshold |
Requires the threads_manage_insights scope.
Retrieval is as important as publishing - here's the read side.
# Your profile GET /me?fields=id,username,threads_biography # Your posts (media objects) GET /me/threads?fields=id,text,media_type,media_url, permalink,timestamp,topic_tag # A single post GET /{media_id}?fields=id,text,media_type,children # Public search (advanced access) GET /keyword_search?q=coffee&search_mode=TAG &media_type=TEXT_POST
Read threads, manage replies, and - since 2026 - approve them before they go live.
Fetch replies to a post and full conversation trees, with author, text, and timestamps for each node.
Post replies via the publish flow with reply_to_id, and hide or restrict replies that cross your lines.
2026's reply-approval controls let workflows hold outbound replies for human sign-off - the API-level safety net for automation.
Scopes: threads_read_repliesthreads_manage_repliesthreads_manage_mentions
Stop polling. Webhooks deliver publish and delete events to your endpoint the moment they happen.
# 1. Subscribe in the app dashboard: callback URL + verify token # 2. Meta verifies your endpoint GET https://you.dev/webhooks/threads ?hub.mode=subscribe&hub.challenge=1158201&hub.verify_token=… → respond with hub.challenge # 3. Events arrive as signed POSTs POST https://you.dev/webhooks/threads { "entry": [{ "changes": [{ "field": "threads", "value": { "event": "published", "media_id": "…" } }] }] } # 4. Verify X-Hub-Signature-256, then trigger your workflow
Four proven shapes for building Threads into a product.
| Pattern | Shape | Used by |
|---|---|---|
| Scheduler | Queue in DB → cron → publish flow | Buffer-style tools |
| Inbox | Webhooks + replies API → unified queue | Hootsuite-style suites |
| Analytics | Daily insights snapshots → warehouse → BI | Metricool-style dashboards |
| Agent | MCP tools + LLM + approval gates | AI-native automations |
Not every team should build this in-house - here's how to buy it well.
Freelance API developers, automation consultancies (Zapier/Make/n8n specialists), and Meta Business Partners with engineering arms.
"Publish queue + mention webhooks into HubSpot" is buildable in days; "integrate Threads" is a blank check. List endpoints and events explicitly.
The Meta app, tokens, and code repository belong in your accounts. A vendor who insists otherwise is building you a hostage situation.
The complete quickstart, condensed.
Meta for Developers → Create App → add the Threads use case. Note your App ID and Secret.
Invite your Threads account under Roles, and accept the invite in the Threads app's website-permissions settings.
Use the Graph API Explorer (or your OAuth flow) to generate a token with threads_basic and threads_content_publish.
Run the two-step flow from the publishing section above - container, then threads_publish.
GET /me/threads to confirm, then add insights, webhooks, and scheduling as your app grows.
requests is all you need.
import requests BASE = "https://graph.threads.net/v1.0" # publish (two-step) c = requests.post(f"{BASE}/{USER_ID}/threads", params={ "media_type": "TEXT", "text": "Hello from Python 🐍", "access_token": TOKEN}).json() requests.post(f"{BASE}/{USER_ID}/threads_publish", params={ "creation_id": c["id"], "access_token": TOKEN}) # insights for a post m = requests.get(f"{BASE}/{c['id']}/insights", params={ "metric": "views,likes,replies,reposts", "access_token": TOKEN}).json() print(m)
Native fetch, nothing else. Keep tokens server-side.
const BASE = "https://graph.threads.net/v1.0"; // publish (two-step) const c = await fetch(`${BASE}/${USER_ID}/threads?media_type=TEXT` + `&text=${encodeURIComponent("Hello from Node 👋")}` + `&access_token=${TOKEN}`, { method: "POST" }) .then(r => r.json()); await fetch(`${BASE}/${USER_ID}/threads_publish` + `?creation_id=${c.id}&access_token=${TOKEN}`, { method: "POST" }); // express webhook verification app.get("/webhooks/threads", (req, res) => res.send(req.query["hub.challenge"]));
Shown with cURL - swap in Guzzle for real projects.
$base = "https://graph.threads.net/v1.0"; function post($url) { $ch = curl_init($url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $out = json_decode(curl_exec($ch)); curl_close($ch); return $out; } $c = post("$base/$userId/threads?" . http_build_query([ "media_type" => "TEXT", "text" => "Hello from PHP 🐘", "access_token" => $token])); post("$base/$userId/threads_publish?creation_id={$c->id}" . "&access_token=$token");
Rolling windows, per profile - check live headroom any time.
| Action | Limit | Window |
|---|---|---|
| Posts | 250 | Rolling 24 hours |
| Replies | 1,000 | Rolling 24 hours |
| Deletions | 100 | Rolling 24 hours |
| Keyword searches | 500 | Rolling 7 days |
Live quota: GET /{user_id}/threads_publishing_limit. Handle 429s with exponential backoff - well-behaved apps rarely see them.
The full authorization dance in five moves.
Send the user to threads.net/oauth/authorize with your client_id, redirect_uri, and requested scopes.
They review the permissions your app requests and grant access with their Threads account.
Threads redirects back to you with a short-lived authorization code.
Server-side, trade code + app secret at /oauth/access_token for a short-lived user token.
Exchange again at /access_token for a ~60-day token - then refresh before expiry.
Common scopes: threads_basicthreads_content_publishthreads_manage_insightsthreads_manage_repliesthreads_keyword_searchthreads_share_to_instagram
Two token types, one refresh habit.
Fresh from the OAuth exchange, valid for hours - fine for testing, wrong for production.
Exchanged from a short-lived token, valid ~60 days - refresh it on a schedule (a token past 24h old can be refreshed) so users never re-auth.
Users can revoke access anytime from their settings; handle 401s by prompting a clean re-connect, not by failing silently.
Publishing, webhooks, and insights compose into full pipelines - covered in depth on the Automation guide.
Recipes, no-code wiring (Zapier · Make · n8n), and AI-agent patterns live on the Automation & AI Tools guide.
There's exactly one sanctioned way to program Threads - and some genuinely different roads if you want an open ecosystem.
Reverse-engineered clients and headless-browser bots violate Meta's terms and get accounts restricted. Whatever they promise, the official API now does legitimately - don't.
Threads speaks ActivityPub - and so does Mastodon, whose fully open API has no corporate review process. For open-web projects, it's the closest cousin.
A different open ecosystem with a famously accessible API - worth knowing if your product targets text-social broadly rather than Threads specifically.
For reaching Threads' 400M+ users specifically, the official Meta Threads API is the alternative-free answer - free, capable, and actively developed.
Create a Meta app, grab a token, run the two-step flow - your first programmatic post ships this afternoon.
FREE FOREVER · 250 POSTS/DAY · WEBHOOKS INCLUDED