Contents
Prerequisites
- A Facebook account (used to log in to Meta for Developers).
- A Threads account (must be public so the token generator can issue a token; this is also the account you'll be posting to).
Register a Meta developer account
Open https://developers.facebook.com, log in with your Facebook account, and on first use click "Get Started" in the top right, agree to the developer terms, and verify your email/phone to finish registering (skip this if you're already a developer). Then click My Apps at the top to reach the app list.
Create an app (5-step wizard)
On the "Apps" page click the green Create App button in the top right. The wizard has 5 steps: App details → Use case → Business → Requirements → Overview.
2-1 App details
2-2 Use case: check "Access the Threads API"
| 🎯 Create and manage ads with the Marketing API | ☐ |
| 🧵 Access the Threads API Use the Threads API to authenticate users, retrieve profile info, publish threads, reply to threads, manage reply settings, and/or collect insights for your own or managed Threads profiles. | ✔ |
| f Authenticate users and request data with Facebook Login | ☐ |
| 🟢 Connect with customers on WhatsApp | ☐ |
2-3 Business → 2-4 Requirements → 2-5 Overview
- Business: choose I don't want to connect a business portfolio yet (not needed for personal projects), click "Next".
- Requirements (publishing criteria): shows "No requirements found" — click "Next".
- Overview: confirm the name, email, and use case are correct, then click the green Create App button.
Add permissions: publish & reply
The dashboard shows a "App customization and requirements" list — click the first item, Customize use case: Access the Threads API (or left sidebar Use cases → Customize), to reach the "Permissions and features" page.
| Permission / feature | Status | Action |
|---|---|---|
| threads_basic Read the user's own threads and basic profile (required by default) | Ready for testing | Action ▾ |
| threads_content_publish Allows the app to create and publish content on behalf of a Threads profile (required for posting) | Ready for testing | Action ▾ |
| threads_manage_replies Create replies on the user's behalf, hide/unhide replies, and control who can reply (required for replying) | Ready for testing | Action ▾ |
| threads_read_replies Read replies on the user's threads (required to read reply threads) | Ready for testing | Action ▾ |
| threads_delete / threads_keyword_search / threads_manage_insights … | + Add |
- threads_basic is added automatically when the app is created (the base permission every Threads API call needs).
- Find threads_content_publish and click + Add — this is the "publish" permission.
- Find threads_manage_replies and click + Add — this is the "reply" permission.
- It's also worth adding threads_read_replies so you can read reply threads.
Use case "Settings": App ID, secret, and callback URLs
Switch to Settings in the left sidebar (this is the use case's settings, not the app's general settings) — this page has four key pieces of information:
- Threads app ID / secret: these are the client_id / client_secret for an OAuth flow in your code. Keep the secret safe — never put it in frontend code or a public repo.
- Redirect callback URL: where the user is redirected after OAuth authorization completes — it must be HTTPS (tested: localhost is rejected). After typing the URL you must press Enter to turn it into a chip before saving, otherwise you'll get a "form couldn't be saved" error.
- Deauthorize / data deletion callback URLs: endpoints Meta pings when a user revokes authorization or requests data deletion. You can fill in placeholder URLs during development.
Add a Threads tester and generate an access token
- In the "User token generator" click Add or remove Threads testers — this opens the "App roles" page.
- Click Add people → choose Threads tester → enter your Threads username (@handle) → send the invite.
- Open the Threads app on your phone: Settings → Account → Website permissions → Invites, and accept the test invitation.
- Back on the "Settings" page's user token generator, a Generate access token button appears next to your account — click it, log in and authorize on Threads, and you'll get a copyable long-lived access token (valid for 60 days).
Post via the API
Posting on Threads is a two-step process: first create a "media container", then "publish" the container. The endpoint is https://graph.threads.net.
# 1) Create a text post container curl -X POST "https://graph.threads.net/v1.0/me/threads" \ -d "media_type=TEXT" \ -d "text=My first post via the Threads API!" \ -d "access_token=YOUR_ACCESS_TOKEN" # Response {"id": "17888..."} ← this is the container ID # 2) Publish the container (recommended: wait ~30s for processing) curl -X POST "https://graph.threads.net/v1.0/me/threads_publish" \ -d "creation_id=17888..." \ -d "access_token=YOUR_ACCESS_TOKEN" # Response {"id": "18027..."} ← this is the published post ID
Python version:
import requests, time, os TOKEN = os.environ["THREADS_TOKEN"] BASE = "https://graph.threads.net/v1.0" # Create the container r = requests.post(f"{BASE}/me/threads", data={ "media_type": "TEXT", "text": "Posted via Python 🎉", "access_token": TOKEN, }).json() container_id = r["id"] time.sleep(30) # Official recommendation: wait for the container to finish processing before publishing # Publish r = requests.post(f"{BASE}/me/threads_publish", data={ "creation_id": container_id, "access_token": TOKEN, }).json() print("Post ID:", r["id"])
Reply to a thread via the API
Replying is also a two-step process — you just add a reply_to_id parameter when creating the container (requires the threads_manage_replies permission):
# 1) Create a "reply" container: reply_to_id = the post ID being replied to curl -X POST "https://graph.threads.net/v1.0/me/threads" \ -d "media_type=TEXT" \ -d "text=This is a reply posted via the API!" \ -d "reply_to_id=18027..." \ -d "access_token=YOUR_ACCESS_TOKEN" # 2) Publish it the same way with threads_publish curl -X POST "https://graph.threads.net/v1.0/me/threads_publish" \ -d "creation_id=REPLY_CONTAINER_ID" \ -d "access_token=YOUR_ACCESS_TOKEN"
Common reply-management endpoints (threads_read_replies / threads_manage_replies):
| Purpose | Endpoint | Method |
|---|---|---|
| Read replies on a post | /{media_id}/replies | GET |
| Read a full conversation thread | /{media_id}/conversation | GET |
| Hide/show a reply | /{reply_id}/manage_reply (hide=true/false) | POST |
| Restrict who can reply | pass reply_control when creating the container (everyone / accounts_you_follow / mentioned_only) | POST |
FAQ
Q1: The "redirect callback URL" won't save?
Two common causes: (1) the URL isn't HTTPS or uses localhost — switch to a real domain; (2) you didn't press Enter to turn the URL into a chip before saving — tested behavior requires pressing Enter first, then saving.
Q2: No "Generate access token" button in the token generator?
Either the tester hasn't accepted the test invite in the Threads app yet, or the Threads account isn't set to public.
Q3: Posting returns a permission error (#10 or OAuthException)?
Check three things: whether the token has expired (60 days), whether the permission has been added to the use case (step 3), and whether the corresponding scope (threads_content_publish, etc.) was actually granted during authorization.
Q4: How many posts can I make per day?
The current official limit is roughly 250 posts and 1,000 replies per 24 hours. You can check your remaining quota with GET /me/threads_publishing_limit.
Q5: Want other people to use your service?
You'll need to request "Advanced Access" for permissions like threads_basic and threads_content_publish in App Review, submitting usage documentation and a demo video. Once approved, any Threads user can authorize your app.