Skip to content

Threads API

Schedule and automate Threads posts with Zernio API - Text, images, videos, carousels, and thread sequences

Quick Reference

PropertyValue
Character limit500
Images per post10 (carousel)
Videos per post1
Image formatsJPEG, PNG, WebP, GIF
Image max size8 MB (auto-compressed)
Video formatsMP4, MOV
Video max size1 GB
Video max duration5 minutes
Post typesText, Image, Video, Carousel, Thread sequence
SchedulingYes
Inbox (Comments)Reply + delete + hide only
Inbox (DMs)No
AnalyticsLimited

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:

typescript
const { post } = await zernio.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);
python
result = client.posts.create_post(
    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']}")
bash
curl -X POST https://zernio.com/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.

typescript
const { post } = await zernio.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);
python
result = client.posts.create_post(
    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']}")
bash
curl -X POST https://zernio.com/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.

typescript
const { post } = await zernio.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);
python
result = client.posts.create_post(
    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']}")
bash
curl -X POST https://zernio.com/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.

typescript
const { post } = await zernio.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);
python
result = client.posts.create_post(
    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']}")
bash
curl -X POST https://zernio.com/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
  }'

Up to 10 images in a single swipeable post.

typescript
const { post } = await zernio.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);
python
result = client.posts.create_post(
    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']}")
bash
curl -X POST https://zernio.com/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.

> Note: When threadItems is provided, the top-level content field is used only for display and search purposes, it is NOT published. You must include your first post as threadItems[0].

typescript
const { post } = await zernio.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);
python
result = client.posts.create_post(
    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']}")
bash
curl -X POST https://zernio.com/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

PropertyRequirement
Max images10 per post (carousel)
FormatsJPEG, PNG, WebP, GIF
Max file size8 MB per image (auto-compressed)
Recommended1080 x 1350 px (4:5 portrait)

Aspect Ratios

RatioDimensionsNotes
4:51080 x 1350 pxPortrait, recommended
1:11080 x 1080 pxSquare
16:91080 x 608 pxLandscape

Videos

PropertyRequirement
Max videos1 per post
FormatsMP4, MOV
Max file size1 GB
Max duration5 minutes
Aspect ratio9:16 (vertical), 16:9 (landscape), 1:1 (square)
Resolution1080p recommended
CodecH.264
Frame rate30 fps recommended
AudioAAC, 128 kbps

Platform-Specific Fields

All fields go inside platformSpecificData on the Threads platform entry.

FieldTypeDescription
topic_tagstringTopic tag for categorization/discoverability. 1-50 characters, cannot contain periods (.) or ampersands (&). When provided, overrides auto-extraction from content hashtags.
threadItemsArray<{content, mediaItems?}>Complete sequence of posts in a Threads thread. The first item becomes the root post and must be provided as threadItems[0]. When threadItems is provided, top-level content is for display/search only and is NOT published.

Topic Tags

Use platformSpecificData.topic_tag to explicitly set the Threads topic tag for a post.

> Note: If you set topic_tag, it overrides any topic tag that Threads might auto-extract from hashtags in your content.

bash
curl -X POST https://zernio.com/api/v1/posts \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Building better APIs starts with better docs.",
    "platforms": [{
      "platform": "threads",
      "accountId": "YOUR_ACCOUNT_ID",
      "platformSpecificData": {
        "topic_tag": "APIDesign"
      }
    }],
    "publishNow": true
  }'
typescript
const { post } = await zernio.posts.createPost({
  content: 'Building better APIs starts with better docs.',
  platforms: [{
    platform: 'threads',
    accountId: 'YOUR_ACCOUNT_ID',
    platformSpecificData: {
      topic_tag: 'APIDesign'
    }
  }],
  publishNow: true
});
console.log('Posted to Threads!', post._id);
python
result = client.posts.create_post(
    content="Building better APIs starts with better docs.",
    platforms=[{
        "platform": "threads",
        "accountId": "YOUR_ACCOUNT_ID",
        "platformSpecificData": {
            "topic_tag": "APIDesign"
        }
    }],
    publish_now=True
)
post = result.post
print(f"Posted to Threads! {post['_id']}")

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-Type header
  • 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

> Included — Analytics is bundled with every paid account on the Usage plan.

Available metrics via the Analytics API:

MetricAvailable
Impressions
Likes
Comments
Shares
Views
typescript
const analytics = await zernio.analytics.getAnalytics({
  platform: 'threads',
  fromDate: '2024-01-01',
  toDate: '2024-01-31'
});
console.log(analytics.posts);
python
analytics = client.analytics.get_analytics(
    platform="threads",
    from_date="2024-01-01",
    to_date="2024-01-31"
)
print(analytics["posts"])
bash
curl "https://zernio.com/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 Zernio's platform (7,705 failures out of 53,014 attempts). Here are the most frequent errors and how to fix them:

ErrorMeaningFix
"Param text must be at most 500 characters long."Post exceeds the 500 character limitShorten 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 URLURL 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 restrictedCheck your account status on Instagram. Resolve any policy violations before retrying.
"Publishing failed due to max retries reached"All publishing retries were exhaustedThis is usually temporary. Wait a few minutes and retry manually.

Inbox

> Included — Inbox (DMs, comments, reviews) is bundled with every paid account on the Usage plan.

Threads supports comment management through the unified Inbox API. Threads does not have direct messaging.

Comments

FeatureSupported
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.

  • 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