PostPost

Twitter Threads

Post tweet threads (tweetstorms) to X/Twitter programmatically using the PostPost REST API. A simpler alternative to manually chaining tweets with the Twitter API v2.

Twitter Thread API Overview

Creating a Twitter thread traditionally requires:

  1. Posting the first tweet
  2. Capturing the tweet ID
  3. Posting each subsequent tweet as a reply using in_reply_to_tweet_id
  4. Handling errors and partial failures

PostPost handles all of this automatically with a single API call.

Keywords: Twitter thread API, tweet thread API, post tweetstorm API, Twitter API thread, X API thread, multi-tweet API, tweet chain API, create Twitter thread programmatically, automate tweet threads, Twitter thread automation, post multiple tweets API

Quick Example

const response = await fetch('https://api.postpost.dev/api/v1/create-post', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'YOUR_API_KEY'
  },
  body: JSON.stringify({
    content: `I've been building in public for 6 months. Here's everything I learned.

First, consistency beats intensity. Posting daily, even small updates, builds more momentum than sporadic big announcements.

Second, share your failures. People connect more with struggles than successes. My most engaging posts were about things that went wrong.

Third, engage genuinely. Reply to comments, ask questions, be curious about others' work. The algorithm rewards conversations.

Finally, don't chase vanity metrics. Focus on connecting with the right people, not the most people.`,
    platforms: ['twitter-123456']
  })
});

const data = await response.json();
console.log('Thread posted:', data);

This will automatically:

  • Split into 4+ tweets at sentence boundaries
  • Add (1/N) numbering to each tweet
  • Post each as a reply to the previous
  • Return all tweet IDs

How Twitter Threads Work

The Official Twitter API v2 Way

With the official Twitter API, creating a thread requires multiple sequential requests:

// Step 1: Post first tweet
const tweet1 = await client.v2.tweet({ text: "First tweet (1/3)" });

// Step 2: Post reply to first tweet
const tweet2 = await client.v2.tweet({
  text: "Second tweet (2/3)",
  reply: { in_reply_to_tweet_id: tweet1.data.id }
});

// Step 3: Post reply to second tweet
const tweet3 = await client.v2.tweet({
  text: "Third tweet (3/3)",
  reply: { in_reply_to_tweet_id: tweet2.data.id }
});

The PostPost Way

// Single request - PostPost handles everything
const response = await fetch('https://api.postpost.dev/api/v1/create-post', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'YOUR_API_KEY'
  },
  body: JSON.stringify({
    content: "First tweet\n\n---\n\nSecond tweet\n\n---\n\nThird tweet",
    platforms: ['twitter-123456']
  })
});

Thread Formatting Options

Automatic Splitting

Content over 280 characters is automatically split:

  • At paragraph breaks (\n\n) first
  • At sentence endings (. , ! , ? ) second
  • At word boundaries as fallback
  • (1/N) markers added automatically

Manual Thread Parts with ---

const content = `Hook: Why most developers fail at Twitter.

---

Mistake #1: They only share finished work. Share the process, the bugs, the learning moments.

---

Mistake #2: They don't engage. Twitter is social. Reply to others, join conversations.

---

Mistake #3: Inconsistency. Tweet daily, even if it's just a quick update.

---

The fix? Treat it like a dev log, not a highlight reel. Your journey IS the content.`;

Manual Thread Parts with Markers

const content = `Hook: Why most developers fail at Twitter. (1/5)

Mistake #1: They only share finished work. (2/5)

Mistake #2: They don't engage with others. (3/5)

Mistake #3: Inconsistency in posting schedule. (4/5)

The fix? Treat Twitter like a dev log, not a highlight reel. (5/5)`;

Character Limits

Account TypePer-Tweet LimitThread Marker Space
Standard280 characters~8 chars for (X/N)
X Premium25,000 characters~8 chars for (X/N)

PostPost automatically reserves space for thread markers.

Emoji Counting

Emojis count as 2 characters on X/Twitter. PostPost accounts for this:

// This tweet is 282 "display" characters but 284 Twitter characters
const content = "Hello! 👋 This is a test tweet with emojis 🚀";
// PostPost correctly calculates: 280 + 4 (2 emojis × 2) = 284

Adding Media to Threads

Images and videos attach to the first tweet only:

// Step 1: Create thread
const postResponse = await fetch('https://api.postpost.dev/api/v1/create-post', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'YOUR_API_KEY'
  },
  body: JSON.stringify({
    content: `Check out this new feature! 🎉

---

Here's how it works: [technical explanation]

---

Try it out and let me know what you think!`,
    platforms: ['twitter-123']
  })
});

const { postGroupId } = await postResponse.json();

// Step 2: Get upload URL for image (goes to first tweet)
const urlRes = await fetch('https://api.postpost.dev/api/v1/get-upload-url', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'YOUR_API_KEY'
  },
  body: JSON.stringify({
    fileName: 'screenshot.jpg',
    contentType: 'image/jpeg',
    type: 'image',
    postGroupId
  })
});
const { uploadUrl } = await urlRes.json();

// Step 3: Upload file directly to S3
await fetch(uploadUrl, {
  method: 'PUT',
  headers: { 'Content-Type': 'image/jpeg' },
  body: screenshotFile
});

Media Limits

  • Images: Up to 4 per tweet (first tweet only)
  • Video: 1 per tweet (first tweet only)
  • Format: All images are auto-converted to PNG (1000px max width) before upload to Twitter
  • Note: Cannot mix images and video in the same tweet

Scheduling Twitter Threads

Note: scheduledTime is optional in the REST API (omitting it creates a draft). However, in the MCP server schema, scheduledTime is required.

Schedule a thread for optimal posting time:

const response = await fetch('https://api.postpost.dev/api/v1/create-post', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': 'YOUR_API_KEY'
  },
  body: JSON.stringify({
    content: `Your thread content here...`,
    platforms: ['twitter-123'],
    scheduledTime: '2026-03-15T14:00:00.000Z'  // 2 PM UTC
  })
});

Rate Limits

Twitter/X API has strict rate limits:

TierMonthly LimitPer 15 MinutesPer User
Free500 tweets~17Limited
Basic ($100/mo)10,000100100
Pro ($5,000/mo)1,000,000HigherHigher

Important: Each tweet in a thread counts as a separate tweet toward your limit. A 5-tweet thread uses 5 tweets from your quota.

Error Handling

Partial Thread Failure

If tweets 1-3 succeed but tweet 4 fails:

{
  "status": "partially_published",
  "error": "Twitter thread partially published (3/5): Rate limit exceeded",
  "publishedIds": ["123", "456", "789"],
  "headTweetId": "123"
}

The published tweets remain live. PostPost saves progress so you know which parts failed.

Common Errors

ErrorCauseSolution
Rate limit exceededToo many requestsWait 15 min or upgrade tier
Character limit exceededTweet too longCheck emoji counting, reduce content
Duplicate contentSame tweet posted recentlyVary your content

Python Example

import requests

response = requests.post(
    'https://api.postpost.dev/api/v1/create-post',
    headers={
        'Content-Type': 'application/json',
        'x-api-key': 'YOUR_API_KEY'
    },
    json={
        'content': '''Thread: 5 Python tips I wish I knew earlier.

---

1. Use enumerate() instead of range(len()). Cleaner and more Pythonic.

---

2. F-strings are faster than .format() and way more readable.

---

3. List comprehensions aren't just shorter—they're actually faster.

---

4. Use `if __name__ == "__main__":` in every script. Future you will thank you.

---

5. The walrus operator `:=` is underrated. Assign and use in one line.''',
        'platforms': ['twitter-123']
    }
)

print(response.json())

cURL Example

curl -X POST https://api.postpost.dev/api/v1/create-post \
  -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{
    "content": "First tweet of my thread\n\n---\n\nSecond tweet continues the story\n\n---\n\nFinal tweet with the conclusion!",
    "platforms": ["twitter-123456"]
  }'

Why Use PostPost for Twitter Threads?

FeaturePostPostTwitter API v2 Direct
Thread creationSingle API callMultiple sequential calls
Content splittingAutomaticManual implementation
Error recoveryBuilt-in partial saveManual handling
Rate limit handlingAutomatic errorsManual tracking
Multi-platformYes (+ Threads, LinkedIn, etc.)Twitter only

Post Twitter threads with a single API call using PostPost.

On this page