Threads API
Schedule and automate Threads posts with Late API - Text, images, videos, carousels, and thread sequences
Quick Reference
| Property | Value |
|---|---|
| Character limit | 500 |
| Images per post | 10 (carousel) |
| Videos per post | 1 |
| Image formats | JPEG, PNG, WebP, GIF |
| Image max size | 8 MB (auto-compressed) |
| Video formats | MP4, MOV |
| Video max size | 1 GB |
| Video max duration | 5 minutes |
| Post types | Text, Image, Video, Carousel, Thread sequence |
| Scheduling | Yes |
| Inbox (Comments) | Reply + delete + hide only (add-on) |
| Inbox (DMs) | No |
| Analytics | Limited |
Before You Start
Threads has a 500 character limit. This is the #1 failure -- users cross-posting from LinkedIn (3,000), Facebook (63,000), or even Instagram (2,200) captions will fail. Use customContent to provide a shorter Threads version.
Threads is connected to your Instagram account. You must have an Instagram Business or Creator account with Threads enabled. Losing Instagram access means losing Threads.
Additional requirements:
- Connected via Instagram authentication (same Facebook app)
- If your Instagram account is restricted, Threads posting fails too
- Rate limit: 250 API-published posts per 24-hour window
Quick Start
Post to Threads in under 60 seconds:
const { post } = await late.posts.createPost({
content: 'Sharing some thoughts on building in public',
platforms: [
{ platform: 'threads', accountId: 'YOUR_ACCOUNT_ID' }
],
publishNow: true
});
console.log('Posted to Threads!', post._id);result = client.posts.create(
content="Sharing some thoughts on building in public",
platforms=[
{"platform": "threads", "accountId": "YOUR_ACCOUNT_ID"}
],
publish_now=True
)
post = result.post
print(f"Posted to Threads! {post['_id']}")curl -X POST https://getlate.dev/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Sharing some thoughts on building in public",
"platforms": [
{"platform": "threads", "accountId": "YOUR_ACCOUNT_ID"}
],
"publishNow": true
}'Content Types
Text Post
Threads is one of the few platforms that supports text-only posts -- no media required. Up to 500 characters.
const { post } = await late.posts.createPost({
content: 'Hot take: the best API is the one with the best docs.',
platforms: [
{ platform: 'threads', accountId: 'YOUR_ACCOUNT_ID' }
],
publishNow: true
});
console.log('Text post created!', post._id);result = client.posts.create(
content="Hot take: the best API is the one with the best docs.",
platforms=[
{"platform": "threads", "accountId": "YOUR_ACCOUNT_ID"}
],
publish_now=True
)
post = result.post
print(f"Text post created! {post['_id']}")curl -X POST https://getlate.dev/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Hot take: the best API is the one with the best docs.",
"platforms": [
{"platform": "threads", "accountId": "YOUR_ACCOUNT_ID"}
],
"publishNow": true
}'Image Post
A single image with an optional caption.
const { post } = await late.posts.createPost({
content: 'New office setup is looking great',
mediaItems: [
{ type: 'image', url: 'https://cdn.example.com/office.jpg' }
],
platforms: [
{ platform: 'threads', accountId: 'YOUR_ACCOUNT_ID' }
],
publishNow: true
});
console.log('Image post created!', post._id);result = client.posts.create(
content="New office setup is looking great",
media_items=[
{"type": "image", "url": "https://cdn.example.com/office.jpg"}
],
platforms=[
{"platform": "threads", "accountId": "YOUR_ACCOUNT_ID"}
],
publish_now=True
)
post = result.post
print(f"Image post created! {post['_id']}")curl -X POST https://getlate.dev/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "New office setup is looking great",
"mediaItems": [
{"type": "image", "url": "https://cdn.example.com/office.jpg"}
],
"platforms": [
{"platform": "threads", "accountId": "YOUR_ACCOUNT_ID"}
],
"publishNow": true
}'Video Post
A single video with an optional caption. Max 1 GB, up to 5 minutes long.
const { post } = await late.posts.createPost({
content: 'Behind the scenes of our latest product launch',
mediaItems: [
{ type: 'video', url: 'https://cdn.example.com/launch.mp4' }
],
platforms: [
{ platform: 'threads', accountId: 'YOUR_ACCOUNT_ID' }
],
publishNow: true
});
console.log('Video post created!', post._id);result = client.posts.create(
content="Behind the scenes of our latest product launch",
media_items=[
{"type": "video", "url": "https://cdn.example.com/launch.mp4"}
],
platforms=[
{"platform": "threads", "accountId": "YOUR_ACCOUNT_ID"}
],
publish_now=True
)
post = result.post
print(f"Video post created! {post['_id']}")curl -X POST https://getlate.dev/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Behind the scenes of our latest product launch",
"mediaItems": [
{"type": "video", "url": "https://cdn.example.com/launch.mp4"}
],
"platforms": [
{"platform": "threads", "accountId": "YOUR_ACCOUNT_ID"}
],
"publishNow": true
}'Carousel
Up to 10 images in a single swipeable post.
const { post } = await late.posts.createPost({
content: 'Product launch day! Here are all the new features:',
mediaItems: [
{ type: 'image', url: 'https://cdn.example.com/feature1.jpg' },
{ type: 'image', url: 'https://cdn.example.com/feature2.jpg' },
{ type: 'image', url: 'https://cdn.example.com/feature3.jpg' }
],
platforms: [
{ platform: 'threads', accountId: 'YOUR_ACCOUNT_ID' }
],
publishNow: true
});
console.log('Carousel posted!', post._id);result = client.posts.create(
content="Product launch day! Here are all the new features:",
media_items=[
{"type": "image", "url": "https://cdn.example.com/feature1.jpg"},
{"type": "image", "url": "https://cdn.example.com/feature2.jpg"},
{"type": "image", "url": "https://cdn.example.com/feature3.jpg"}
],
platforms=[
{"platform": "threads", "accountId": "YOUR_ACCOUNT_ID"}
],
publish_now=True
)
post = result.post
print(f"Carousel posted! {post['_id']}")curl -X POST https://getlate.dev/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"content": "Product launch day! Here are all the new features:",
"mediaItems": [
{"type": "image", "url": "https://cdn.example.com/feature1.jpg"},
{"type": "image", "url": "https://cdn.example.com/feature2.jpg"},
{"type": "image", "url": "https://cdn.example.com/feature3.jpg"}
],
"platforms": [
{"platform": "threads", "accountId": "YOUR_ACCOUNT_ID"}
],
"publishNow": true
}'Thread Sequence
Create connected posts (root + replies) using threadItems. The first item is the root post and subsequent items become replies in order. Each item can have its own text and media.
const { post } = await late.posts.createPost({
platforms: [{
platform: 'threads',
accountId: 'YOUR_ACCOUNT_ID',
platformSpecificData: {
threadItems: [
{
content: 'Here is a thread about API design',
mediaItems: [{ type: 'image', url: 'https://cdn.example.com/cover.jpg' }]
},
{ content: '1/ First, let us talk about REST principles...' },
{
content: '2/ Authentication is crucial. Here is what we recommend...',
mediaItems: [{ type: 'image', url: 'https://cdn.example.com/auth-diagram.jpg' }]
},
{ content: '3/ Finally, always version your API! /end' }
]
}
}],
publishNow: true
});
console.log('Thread posted!', post._id);result = client.posts.create(
platforms=[{
"platform": "threads",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {
"threadItems": [
{
"content": "Here is a thread about API design",
"mediaItems": [{"type": "image", "url": "https://cdn.example.com/cover.jpg"}]
},
{"content": "1/ First, let us talk about REST principles..."},
{
"content": "2/ Authentication is crucial. Here is what we recommend...",
"mediaItems": [{"type": "image", "url": "https://cdn.example.com/auth-diagram.jpg"}]
},
{"content": "3/ Finally, always version your API! /end"}
]
}
}],
publish_now=True
)
post = result.post
print(f"Thread posted! {post['_id']}")curl -X POST https://getlate.dev/api/v1/posts \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"platforms": [{
"platform": "threads",
"accountId": "YOUR_ACCOUNT_ID",
"platformSpecificData": {
"threadItems": [
{
"content": "Here is a thread about API design",
"mediaItems": [{"type": "image", "url": "https://cdn.example.com/cover.jpg"}]
},
{
"content": "1/ First, let us talk about REST principles..."
},
{
"content": "2/ Authentication is crucial. Here is what we recommend...",
"mediaItems": [{"type": "image", "url": "https://cdn.example.com/auth-diagram.jpg"}]
},
{
"content": "3/ Finally, always version your API! /end"
}
]
}
}],
"publishNow": true
}'Media Requirements
Images
| Property | Requirement |
|---|---|
| Max images | 10 per post (carousel) |
| Formats | JPEG, PNG, WebP, GIF |
| Max file size | 8 MB per image (auto-compressed) |
| Recommended | 1080 x 1350 px (4:5 portrait) |
Aspect Ratios
| Ratio | Dimensions | Notes |
|---|---|---|
| 4:5 | 1080 x 1350 px | Portrait, recommended |
| 1:1 | 1080 x 1080 px | Square |
| 16:9 | 1080 x 608 px | Landscape |
Videos
| Property | Requirement |
|---|---|
| Max videos | 1 per post |
| Formats | MP4, MOV |
| Max file size | 1 GB |
| Max duration | 5 minutes |
| Aspect ratio | 9:16 (vertical), 16:9 (landscape), 1:1 (square) |
| Resolution | 1080p recommended |
| Codec | H.264 |
| Frame rate | 30 fps recommended |
| Audio | AAC, 128 kbps |
Platform-Specific Fields
All fields go inside platformSpecificData on the Threads platform entry.
| Field | Type | Description |
|---|---|---|
threadItems | Array<{content, mediaItems?}> | Creates a thread sequence. First item is the root post, subsequent items become replies in order. Each item can have its own content (string) and optional mediaItems (array of media objects). |
Media URL Requirements
These do not work as media URLs:
- Google Drive -- returns an HTML download page, not the file
- Dropbox -- returns an HTML preview page
- OneDrive / SharePoint -- returns HTML
- iCloud -- returns HTML
Test your URL in an incognito browser window. If you see a webpage instead of the raw image or video, it will not work.
Threads uses the same media infrastructure as Instagram. Media URLs must be:
- Publicly accessible (no authentication required)
- Returning actual media bytes with the correct
Content-Typeheader - Not behind redirects that resolve to HTML pages
WebP images may fail -- use JPEG or PNG for the most reliable results.
Images above 8 MB are auto-compressed. Original files are preserved.
Analytics
Requires Analytics add-on
Available metrics via the Analytics API:
| Metric | Available |
|---|---|
| Impressions | ✅ |
| Likes | ✅ |
| Comments | ✅ |
| Shares | ✅ |
| Views | ✅ |
const analytics = await late.analytics.getAnalytics({
platform: 'threads',
fromDate: '2024-01-01',
toDate: '2024-01-31'
});
console.log(analytics.posts);analytics = client.analytics.get(
platform="threads",
from_date="2024-01-01",
to_date="2024-01-31"
)
print(analytics["posts"])curl "https://getlate.dev/api/v1/analytics?platform=threads&fromDate=2024-01-01&toDate=2024-01-31" \
-H "Authorization: Bearer YOUR_API_KEY"What You Can't Do
These features are not available through the Threads API:
- Create polls
- Use GIF search
- Edit posts after publishing
- See who liked or reposted
- Create quote posts
- Post new top-level comments (reply-only)
- Like or unlike comments
- Send DMs
Common Errors
Threads has a 14.5% failure rate across Late's platform (7,705 failures out of 53,014 attempts). Here are the most frequent errors and how to fix them:
| Error | Meaning | Fix |
|---|---|---|
| "Param text must be at most 500 characters long." | Post exceeds the 500 character limit | Shorten to 500 characters. Use customContent for cross-platform posts so each platform gets its own version. |
| "Media download has failed. The media URI doesn't meet our requirements." (2207052) | Threads cannot fetch media from the provided URL | URL must return actual media bytes, not an HTML page. WebP may fail -- use JPEG or PNG instead. |
| "Instagram account is restricted." (2207050) | The linked Instagram account is restricted | Check your account status on Instagram. Resolve any policy violations before retrying. |
| "Publishing failed due to max retries reached" | All publishing retries were exhausted | This is usually temporary. Wait a few minutes and retry manually. |
Inbox
Requires Inbox add-on — Build: +$10/mo · Accelerate: +$50/unit · Unlimited: +$1,000/mo
Threads supports comment management through the unified Inbox API. Threads does not have direct messaging.
Comments
| Feature | Supported |
|---|---|
| List comments on posts | ✅ |
| Post new comment | ❌ |
| Reply to comments | ✅ |
| Delete comments | ✅ |
| Like/unlike comments | ❌ |
| Hide/unhide comments | ✅ |
Limitations
- No DMs - Threads API does not support direct messages
- No comment likes - Threads API does not support liking comments
- Reply-only - Cannot post new top-level comments, only replies
See Comments API Reference for endpoint details.
Related Endpoints
- Connect Threads Account - Via Instagram authentication
- Create Post - Post creation and scheduling
- Upload Media - Image and video uploads
- Analytics - Performance metrics
- Comments - Reply to comments