![Threads API Developer Guide [2025] — Application Process, Integration Examples, Endpoint List, Real-World Use Cases](/_next/image?url=%2Fimg%2Fthreads-api-architecture-diagram.jpg&w=3840&q=75)
Threads API Developer Guide [2025] — Application Process, Integration Examples, Endpoint List, Real-World Use Cases
Complete Threads API tutorial! 5-step developer application process, basic API integration examples (authentication, GET, POST, DELETE), full list of common API endpoints, error handling, real-world use cases, and security best practices.
Threads MarketingWant to automate your Threads post management through code? Looking to build a Threads analytics tool or bot?
The Threads API is part of the Meta Graph API, giving developers programmatic access to Threads features. This guide walks you through everything from scratch — the application process, basic integration examples, common API endpoints, error handling, real-world use cases, and security best practices.
What Is the Threads API? Features, Scope, and Architecture
What Is the Threads API?
The Threads API is Meta's official interface for developers, allowing you to:
- Create, read, update, and delete Threads posts
- Retrieve user profile information
- Read post engagement data (likes, comments, reposts)
- Manage comments and replies
- Retrieve follower and following data
Threads API vs. Meta Graph API
The Threads API is an extension of the Meta Graph API:
| Item | Details |
|---|---|
Infrastructure | Based on Meta Graph API 4.0+ |
Authentication | Uses Meta developer app + Access Token |
API Endpoint | https://graph.threads.net/v1.0/ |
Permission Scope | Requires specific permissions (threads_basic, threads_content_publish, etc.) |
Documentation |
API Feature Limitations (2025 Version)
Currently supported features:
- ✓ Publish text posts (with images and videos)
- ✓ Read post content and engagement data
- ✓ Delete your own posts
- ✓ Read profile information
- ✓ Manage comments and replies
Currently unsupported features:
- ✗ Edit published posts (Threads itself doesn't support this)
- ✗ Manage direct messages (Threads DMs integrate with IG — use the Instagram API instead)
- ✗ Circle feature (no API support currently)
- ✗ Batch operations (must implement loops manually)
Limits and quotas:
- Post limit: 200 per hour (standard app)
- Read limit: 200 requests per hour
- Enterprise-level apps can apply for higher quotas
Developer Application Process (5 Steps)
Step 1: Register a Meta Developer Account
Prerequisites:
- A Facebook account (with verified email)
- A Threads account (linked to Facebook)
Steps:
- Go to Meta for Developers
- Click "Log In" in the top-right corner and sign in with your Facebook account
- First-time login will prompt you to register as a developer
- Fill in basic information:
- Name and email
- Development purpose (choose "Individual" or "Business")
- Agree to the developer terms
- Complete phone verification (if required)
Time required: About 5 minutes
Step 2: Create an Application
Steps:
- In the developer dashboard, click "My Apps"
- Click "Create App"
- Select the app type:
- "Business": If you're building commercial tools for clients
- "Consumer": If you're building an app for end users
- "Other": Personal projects or experiments
- Fill in app information:
- App name (e.g., "My Threads Manager")
- Contact email
- Business account (optional)
- Click "Create App"
Time required: About 3 minutes
Step 3: Add the Threads API Product
Steps:
- Go to the app dashboard
- Find "Add Product" in the left sidebar
- Find "Threads API" (or "Threads") and click "Set Up"
- The system will automatically add the necessary permissions and settings
- Record the following important information:
- App ID
- App Secret — click "Show" and copy it
Important:
- Keep the App Secret secure — never publish it or commit it to GitHub
- Store it using environment variables
Time required: About 2 minutes
Step 4: Configure Permissions and OAuth Redirect URI
Steps:
-
Set permission scopes:
- Left sidebar → "Threads API" → "Permissions & Features"
- Check the permissions you need:
threads_basic: Read basic profile informationthreads_content_publish: Publish poststhreads_manage_insights: Read analytics datathreads_manage_replies: Manage comments and repliesthreads_read_replies: Read comments
-
Set OAuth redirect URI:
- Left sidebar → "Settings" → "Basic"
- Find "App Domains" and enter your domain (e.g.,
example.com) - Under "Valid OAuth Redirect URIs", enter:
- Development:
http://localhost:3000/auth/callback - Production:
https://yourdomain.com/auth/callback
- Development:
- Click "Save Changes"
Time required: About 5 minutes
Step 5: Obtain an Access Token
The Threads API uses OAuth 2.0 authentication — you need a user Access Token.
Method 1: Using the Meta Graph API Explorer (for testing)
- Go to Graph API Explorer
- Select your app at the top
- Click "User or Page" → select your Threads account
- Click "Get Access Token"
- Check the required permissions (threads_basic, threads_content_publish)
- Click "Generate Access Token"
- Copy the Access Token
Note: This token is short-lived (1–2 hours) and is only suitable for testing.
Method 2: Using the OAuth Flow (for production)
The full OAuth flow involves these steps:
- Redirect the user to the authorization page:
https://www.facebook.com/v18.0/dialog/oauth?
client_id={APP_ID}&
redirect_uri={REDIRECT_URI}&
scope=threads_basic,threads_content_publish&
response_type=code
- After the user authorizes, receive an Authorization Code
- Exchange the code for an Access Token:
curl -X GET "https://graph.facebook.com/v18.0/oauth/access_token?
client_id={APP_ID}&
client_secret={APP_SECRET}&
redirect_uri={REDIRECT_URI}&
code={AUTHORIZATION_CODE}"
- Receive the Access Token (usable for API requests)
Method 3: Long-lived Token (recommended)
Convert a short-lived token to a long-lived token (valid for 60 days):
curl -X GET "https://graph.facebook.com/v18.0/oauth/access_token?
grant_type=fb_exchange_token&
client_id={APP_ID}&
client_secret={APP_SECRET}&
fb_exchange_token={SHORT_LIVED_TOKEN}"
Time required: 5–15 minutes (depending on method)
Basic API Integration Examples
The following examples use Python (requests library) and JavaScript (Node.js + axios) to demonstrate basic CRUD operations.
Environment Setup
Python:
pip install requests
JavaScript (Node.js):
npm install axios dotenv
Environment variables (.env file):
APP_ID=your_app_id
APP_SECRET=your_app_secret
ACCESS_TOKEN=your_access_token
THREADS_USER_ID=your_threads_user_id
Example 1: Authentication Test (GET)
Verify that the Access Token is valid and retrieve basic user info.
Python:
import requests
import os
ACCESS_TOKEN = os.getenv('ACCESS_TOKEN')
BASE_URL = 'https://graph.threads.net/v1.0'
def get_user_profile():
url = f"{BASE_URL}/me"
params = {
'fields': 'id,username,threads_profile_picture_url,threads_biography',
'access_token': ACCESS_TOKEN
}
response = requests.get(url, params=params)
if response.status_code == 200:
data = response.json()
print("User info:")
print(f"ID: {data.get('id')}")
print(f"Username: {data.get('username')}")
print(f"Bio: {data.get('threads_biography')}")
return data
else:
print(f"Error: {response.status_code}")
print(response.json())
return None
get_user_profile()
JavaScript (Node.js):
const axios = require('axios');
require('dotenv').config();
const ACCESS_TOKEN = process.env.ACCESS_TOKEN;
const BASE_URL = 'https://graph.threads.net/v1.0';
async function getUserProfile() {
try {
const response = await axios.get(`${BASE_URL}/me`, {
params: {
fields: 'id,username,threads_profile_picture_url,threads_biography',
access_token: ACCESS_TOKEN
}
});
console.log('User info:');
console.log(`ID: ${response.data.id}`);
console.log(`Username: ${response.data.username}`);
console.log(`Bio: ${response.data.threads_biography}`);
return response.data;
} catch (error) {
console.error('Error:', error.response.data);
return null;
}
}
getUserProfile();
Expected output:
User info:
ID: 1234567890
Username: example_user
Bio: This is my Threads bio
Example 2: Publish a Text Post (POST)
Python:
def create_text_post(text_content):
url = f"{BASE_URL}/me/threads"
payload = {
'media_type': 'TEXT',
'text': text_content,
'access_token': ACCESS_TOKEN
}
# Step 1: Create media container
response = requests.post(url, data=payload)
if response.status_code == 200:
container_id = response.json().get('id')
print(f"Container ID: {container_id}")
# Step 2: Publish the post
publish_url = f"{BASE_URL}/me/threads_publish"
publish_payload = {
'creation_id': container_id,
'access_token': ACCESS_TOKEN
}
publish_response = requests.post(publish_url, data=publish_payload)
if publish_response.status_code == 200:
post_id = publish_response.json().get('id')
print(f"Post published successfully! Post ID: {post_id}")
return post_id
else:
print("Publish failed:", publish_response.json())
return None
else:
print("Container creation failed:", response.json())
return None
create_text_post("Hello from Threads API!")
Important note:
- Threads post publishing is a two-step process: create container → publish
- This design allows you to preview or validate content before publishing
Example 3: Publish an Image Post (POST)
Python:
def create_image_post(text_content, image_url):
url = f"{BASE_URL}/me/threads"
payload = {
'media_type': 'IMAGE',
'image_url': image_url, # Image must be a publicly accessible URL
'text': text_content,
'access_token': ACCESS_TOKEN
}
response = requests.post(url, data=payload)
if response.status_code == 200:
container_id = response.json().get('id')
publish_url = f"{BASE_URL}/me/threads_publish"
publish_payload = {
'creation_id': container_id,
'access_token': ACCESS_TOKEN
}
publish_response = requests.post(publish_url, data=publish_payload)
if publish_response.status_code == 200:
post_id = publish_response.json().get('id')
print(f"Image post published! Post ID: {post_id}")
return post_id
else:
print("Publish failed:", publish_response.json())
return None
else:
print("Container creation failed:", response.json())
return None
create_image_post(
"Check out this image!",
"https://example.com/image.jpg"
)
Notes:
- Image must be a publicly accessible HTTPS URL
- Supported formats: JPG, PNG
- File size limit: 8 MB
- To upload a local image, first upload it to a CDN or image host
Example 4: Read Post Data (GET)
Python:
def get_post_data(post_id):
url = f"{BASE_URL}/{post_id}"
params = {
'fields': 'id,text,media_type,media_url,timestamp,like_count,replies_count',
'access_token': ACCESS_TOKEN
}
response = requests.get(url, params=params)
if response.status_code == 200:
data = response.json()
print("Post info:")
print(f"ID: {data.get('id')}")
print(f"Content: {data.get('text')}")
print(f"Type: {data.get('media_type')}")
print(f"Likes: {data.get('like_count')}")
print(f"Replies: {data.get('replies_count')}")
print(f"Timestamp: {data.get('timestamp')}")
return data
else:
print("Read failed:", response.json())
return None
get_post_data("YOUR_POST_ID")
Example 5: Delete a Post (DELETE)
Python:
def delete_post(post_id):
url = f"{BASE_URL}/{post_id}"
params = {
'access_token': ACCESS_TOKEN
}
response = requests.delete(url, params=params)
if response.status_code == 200:
print(f"Post {post_id} deleted")
return True
else:
print("Delete failed:", response.json())
return False
delete_post("YOUR_POST_ID")
Warning: Deletion is permanent and cannot be undone!
Complete List of Common API Endpoints
The following are commonly used Threads API endpoints (2025 version):
User Endpoints
| Endpoint | Method | Description | Permission Required |
|---|---|---|---|
/me | GET | Get current user info | threads_basic |
/me/threads | GET | Get user's post list | threads_basic |
/me/threads | POST | Create media container (post step 1) | threads_content_publish |
/me/threads_publish | POST | Publish post (post step 2) | threads_content_publish |
/{user_id} | GET | Get specified user info | threads_basic |
Post Endpoints
| Endpoint | Method | Description | Permission Required |
|---|---|---|---|
/{post_id} | GET | Get a single post | threads_basic |
/{post_id} | DELETE | Delete a post | threads_content_publish |
/{post_id}/insights | GET | Get post analytics | threads_manage_insights |
/{post_id}/replies | GET | Get post reply list | threads_read_replies |
Comments and Replies Endpoints
| Endpoint | Method | Description | Permission Required |
|---|---|---|---|
/{post_id}/comments | GET | Get comments list | threads_read_replies |
/{post_id}/comments | POST | Add a comment | threads_manage_replies |
/{comment_id} | GET | Get a single comment | threads_read_replies |
/{comment_id} | DELETE | Delete a comment | threads_manage_replies |
/{comment_id}/replies | GET | Get comment replies | threads_read_replies |
Analytics Endpoints
| Endpoint | Method | Description | Permission Required |
|---|---|---|---|
/me/threads_insights | GET | Get account-level analytics | threads_manage_insights |
/{post_id}/insights | GET | Get post-level analytics | threads_manage_insights |
Available Fields
User object:
id: User IDusername: Username (@handle)threads_profile_picture_url: Profile picture URLthreads_biography: Bio
Post object:
id: Post IDtext: Post text contentmedia_type: Media type (TEXT, IMAGE, VIDEO)media_url: Media URLtimestamp: Published timelike_count: Like countreplies_count: Reply countquotes_count: Quote/repost countis_reply: Whether this is a replyis_quote_post: Whether this is a quote post
Error Handling and Debugging
Common Error Codes
| Error Code | Description | Solution |
|---|---|---|
400 | Malformed request | Check API parameters and data format |
190 | Access Token invalid or expired | Re-obtain the Access Token |
200 | Insufficient permissions | Confirm the app has the required permissions |
4 | API rate limit exceeded | Reduce request frequency; implement rate limiting |
100 | Missing required parameter | Check the API docs and add the missing parameter |
613 | Transient error | Retry later (use Exponential Backoff) |
Error Handling Best Practices
Python example:
import time
from requests.exceptions import RequestException
def api_request_with_retry(url, params, max_retries=3):
"""
API request with retry mechanism
Uses Exponential Backoff strategy
"""
for attempt in range(max_retries):
try:
response = requests.get(url, params=params)
if response.status_code == 200:
return response.json()
elif response.status_code == 190:
print("Access Token expired — please re-obtain it")
return None
elif response.status_code == 4:
wait_time = 2 ** attempt # Exponential backoff: 1s, 2s, 4s
print(f"Rate limit exceeded — retrying in {wait_time}s...")
time.sleep(wait_time)
continue
else:
error_data = response.json()
print(f"Error {response.status_code}: {error_data}")
return None
except RequestException as e:
print(f"Network error: {e}")
if attempt < max_retries - 1:
time.sleep(2 ** attempt)
continue
return None
print("Max retries reached — request failed")
return None
Debugging Tips
1. Test with Graph API Explorer:
- Go to Graph API Explorer
- Select your app
- Manually test various API endpoints
- Inspect request/response format
2. Check the API version:
- The Threads API is based on Graph API v18.0+
- Make sure your endpoint URLs use the correct version
- Older versions may not support certain features
3. Enable verbose error messages:
params = {
'access_token': ACCESS_TOKEN,
'debug': 'all' # Enable detailed debug info
}
Real-World Use Cases (5 Scenarios)
Scenario 1: Automated Content Publishing Tool
Requirements:
- Schedule Threads posts
- Publish to multiple platforms at once (Threads + IG + Twitter)
- Template-based content with variable substitution
Technical implementation:
import schedule
import time
def scheduled_post():
"""Publish a daily motivational quote at 9 AM"""
quotes = [
"Keep going — success is closer than you think!",
"Every day is a fresh start.",
"Believe in yourself — you've got this!"
]
today_quote = quotes[int(time.time()) % len(quotes)]
create_text_post(today_quote)
print(f"Published today's quote: {today_quote}")
schedule.every().day.at("09:00").do(scheduled_post)
while True:
schedule.run_pending()
time.sleep(60)
Value:
- Saves time on manual posting
- Ensures consistent content cadence
- Increases account activity
Scenario 2: Threads Analytics Dashboard
Requirements:
- Track post engagement (likes, replies, reposts)
- Visualize growth trends
- Find the optimal posting time
Technical implementation:
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime, timedelta
def fetch_posts_analytics(days=30):
"""Get post data for the past N days"""
url = f"{BASE_URL}/me/threads"
params = {
'fields': 'id,text,timestamp,like_count,replies_count',
'limit': 100,
'access_token': ACCESS_TOKEN
}
response = requests.get(url, params=params)
posts = response.json().get('data', [])
df = pd.DataFrame(posts)
df['timestamp'] = pd.to_datetime(df['timestamp'])
cutoff_date = datetime.now() - timedelta(days=days)
df = df[df['timestamp'] > cutoff_date]
df['total_engagement'] = df['like_count'] + df['replies_count']
daily_engagement = df.groupby(df['timestamp'].dt.date)['total_engagement'].sum()
plt.figure(figsize=(12, 6))
plt.plot(daily_engagement.index, daily_engagement.values, marker='o')
plt.title('Threads Engagement Trend — Last 30 Days')
plt.xlabel('Date')
plt.ylabel('Total Engagement')
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig('threads_analytics.png')
print("Analytics chart saved as threads_analytics.png")
return df
fetch_posts_analytics(30)
Scenario 3: Auto-Reply Bot
Requirements:
- Automatically reply to comments containing specific keywords
- Handle FAQs
- Improve customer service efficiency
Technical implementation:
def auto_reply_bot(post_id):
"""Auto-reply to comments containing keywords"""
faq_rules = {
'pricing': 'See our pricing plans at: https://example.com/pricing',
'how to use': 'View the usage guide at: https://example.com/guide',
'support': 'For help, DM us or email [email protected]'
}
url = f"{BASE_URL}/{post_id}/comments"
params = {
'fields': 'id,text,from',
'access_token': ACCESS_TOKEN
}
response = requests.get(url, params=params)
comments = response.json().get('data', [])
for comment in comments:
comment_text = comment.get('text', '')
comment_id = comment.get('id')
for keyword, reply in faq_rules.items():
if keyword in comment_text.lower():
reply_url = f"{BASE_URL}/{comment_id}/replies"
reply_payload = {
'message': reply,
'access_token': ACCESS_TOKEN
}
reply_response = requests.post(reply_url, data=reply_payload)
if reply_response.status_code == 200:
print(f"Replied to comment {comment_id}")
break
auto_reply_bot("YOUR_POST_ID")
Notes:
- Avoid over-automating (can be flagged as spam)
- Add a human review layer
- Follow Meta's automation policies
Scenario 4: Content Backup and Export Tool
Technical implementation:
import json
from datetime import datetime
def backup_all_posts():
"""Back up all posts to a JSON file"""
all_posts = []
url = f"{BASE_URL}/me/threads"
params = {
'fields': 'id,text,media_type,media_url,timestamp,like_count,replies_count',
'limit': 100,
'access_token': ACCESS_TOKEN
}
while url:
response = requests.get(url, params=params)
data = response.json()
all_posts.extend(data.get('data', []))
url = data.get('paging', {}).get('next')
params = {}
backup_filename = f"threads_backup_{datetime.now().strftime('%Y%m%d')}.json"
with open(backup_filename, 'w', encoding='utf-8') as f:
json.dump(all_posts, f, ensure_ascii=False, indent=2)
print(f"Backed up {len(all_posts)} posts to {backup_filename}")
return all_posts
backup_all_posts()
Scenario 5: Cross-Platform Content Sync Tool
Conceptual implementation:
def cross_platform_publish(content, platforms=['threads', 'twitter', 'instagram']):
"""Publish content across platforms"""
results = {}
if 'threads' in platforms:
threads_content = content[:500]
threads_id = create_text_post(threads_content)
results['threads'] = threads_id
if 'twitter' in platforms:
twitter_content = content[:280]
results['twitter'] = "(Requires Twitter API implementation)"
if 'instagram' in platforms:
results['instagram'] = "(Requires Instagram API implementation)"
print("Cross-platform publish complete:")
for platform, post_id in results.items():
print(f" - {platform}: {post_id}")
return results
cross_platform_publish("Hello, multi-platform world!", ['threads'])
Security and Best Practices
1. Access Token Protection
DO (recommended practices):
- ✓ Store tokens in environment variables
- ✓ Never commit tokens to Git
- ✓ Use
.gitignoreto exclude.envfiles - ✓ Rotate Access Tokens regularly
- ✓ Use HTTPS for all transmissions
DON'T (practices to avoid):
- ✗ Hardcode tokens in source code
- ✗ Store in public config files
- ✗ Share with third parties
- ✗ Expose tokens in frontend JavaScript
Example (.gitignore):
.env
*.env
config.json
credentials.json
2. Rate Limiting
Implementing a Rate Limiter:
import time
from collections import deque
class RateLimiter:
"""Simple rate limiter (max 200 requests per hour)"""
def __init__(self, max_requests=200, time_window=3600):
self.max_requests = max_requests
self.time_window = time_window
self.requests = deque()
def can_proceed(self):
now = time.time()
while self.requests and self.requests[0] < now - self.time_window:
self.requests.popleft()
if len(self.requests) < self.max_requests:
self.requests.append(now)
return True
else:
print("Rate limit reached — please wait")
return False
rate_limiter = RateLimiter()
def safe_api_request(url, params):
if rate_limiter.can_proceed():
return requests.get(url, params=params)
else:
return None
3. Data Validation and Sanitization
def sanitize_post_content(text):
"""Clean post content to prevent injection attacks"""
text = text.replace('<', '').replace('>', '')
if len(text) > 500:
text = text[:497] + '...'
text = ' '.join(text.split())
return text
user_input = "<script>alert('xss')</script> Hello!"
safe_content = sanitize_post_content(user_input)
create_text_post(safe_content)
4. Error Logging
import logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('threads_api.log'),
logging.StreamHandler()
]
)
def create_text_post_with_logging(text):
try:
logging.info(f"Attempting to publish post: {text[:50]}...")
post_id = create_text_post(text)
logging.info(f"Post published successfully, ID: {post_id}")
return post_id
except Exception as e:
logging.error(f"Publish failed: {str(e)}")
return None
5. GDPR and Personal Data Protection
Best practices:
- ✓ Clearly communicate data usage to users
- ✓ Provide data deletion functionality
- ✓ Encrypt sensitive data at rest
- ✓ Regularly delete unnecessary logs
- ✓ Comply with Meta's data usage policies
Developer Resources
Official Documentation
Useful Tools
- Postman: API testing tool
- Insomnia: Lightweight API testing tool
- Webhook.site: Test webhook callbacks
- ngrok: Expose local development environment to the internet
Community Resources
- Stack Overflow:
threads-apitag - Reddit: r/webdev, r/API
- GitHub: Search "threads api" for open-source projects
FAQ
Q1: Is the Threads API free?
Answer: Yes, the Threads API itself is free.
You will need:
- A Meta developer account (free)
- Compliance with API request quota limits
- Higher quotas may require applying for enterprise-level permissions
Q2: Can individual developers use the Threads API?
Answer: Yes.
Anyone can register a Meta developer account and use the Threads API — it's not limited to companies or professional developers.
Q3: Which programming languages does the Threads API support?
Answer: Any language that can make HTTP requests.
Common choices:
- Python (requests, httpx)
- JavaScript/Node.js (axios, fetch)
- PHP (cURL, Guzzle)
- Ruby (HTTParty)
- Java (OkHttp, Retrofit)
Q4: How do I get enterprise-level API quotas?
Answer:
- Apply for "App Review" in the developer dashboard
- Explain your app's purpose and necessity
- Provide a privacy policy and terms of service for your app
- Meta's team reviews it (approximately 3–5 business days)
- Higher quotas are granted upon approval
Q5: Can I manage Threads direct messages through the API?
Answer: Not currently.
Threads DMs are integrated into Instagram — you'll need the Instagram Messaging API (which requires additional permission applications).
Q6: Does the Threads API support webhooks?
Answer: Yes, but only for certain events.
Currently supported webhook events:
- New comment notifications
- Post mention notifications
- (More events being added continuously)
Setup: Developer Dashboard → Webhooks → Subscribe to Events
Q7: Do failed API requests count against the quota?
Answer: Yes.
Both successful and failed requests count toward the quota. That's why implementing proper error handling and retry mechanisms is important.
Q8: Can I auto-follow or unfollow people via the API?
Answer: The current Threads API does not support follow/unfollow operations.
This feature may be added in a future version — watch for official announcements.
Related Resources
For more Threads features and tips, check out these articles:
- Threads Complete Guide 2025 | Features, Video Download, DM Settings
- Threads Web & Desktop Usage Guide (advanced developer features)
- Threads & IG Integration/Disconnection Guide
- Threads Direct Message Guide (understanding DM API integration possibilities)
- Threads Circle Complete Guide (Circle feature currently has no API support)
