How-To Guide

How to Post a Twitter Thread
via API

Post a whole X thread in a single API call. Send is_thread and thread_tweets to OpenTweet, publish it now or schedule it, and never manage reply ids or rate limits yourself.

One bearer key • No X developer account • Free 7-day trial

Why Post Threads from the API?

Threads are how substance lands on X. But posting one through the raw X API means chaining each tweet to the previous reply, tracking ids, and dodging rate limits, all before you have paid for a developer account. OpenTweet collapses that into one request.

You send the whole thread as an array of strings and OpenTweet does the chaining. Publish it immediately, schedule it for the exact minute you want, or save it as a draft and batch-schedule a week of threads at once. The same call works from a shell script, a Node service, a cron job, or an autonomous AI agent.

Everything below uses the real base URL, https://opentweet.io/api/v1, and one bearer key with the ot_ prefix. No OAuth, no per-call metering, no api.opentweet.io subdomain. Copy a snippet, swap in your key, and your thread is live.

Step-by-Step: Post a Thread via API

1

Get an API key

Create an OpenTweet account and generate an API key at opentweet.io/developer. Keys use the ot_ prefix. Send it as Authorization: Bearer ot_your_key on every request. There is no X developer account, no OAuth dance, and no $200/mo API minimum. Verify the key works with a quick GET /me before you post anything.

Verify your key first

Run a quick check before you post. A 200 response means the key is live.
bash
curl https://opentweet.io/api/v1/me \
  -H "Authorization: Bearer ot_your_key"
Get a key at opentweet.io/developer.
2

Post the whole thread in one call

Send one POST to /api/v1/posts with is_thread set to true and thread_tweets as an array of strings, one string per tweet. Add publish_now: true to post immediately. OpenTweet chains every tweet into a single reply thread in order, so you never touch reply ids or per-tweet rate limits. To attach media, pass thread_media with one array per tweet in the same order.

curl

bash
curl -X POST https://opentweet.io/api/v1/posts \
  -H "Authorization: Bearer ot_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "is_thread": true,
    "thread_tweets": [
      "How we cut our API latency by 60%. A thread.",
      "First, we moved read traffic to a replica and added a cache in front of it.",
      "Then we batched the writes. Same throughput, a third of the connections."
    ],
    "thread_media": [[], [], []],
    "publish_now": true
  }'

Node.js

javascript
const res = await fetch("https://opentweet.io/api/v1/posts", {
  method: "POST",
  headers: {
    "Authorization": "Bearer ot_your_key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    is_thread: true,
    thread_tweets: [
      "How we cut our API latency by 60%. A thread.",
      "First, we moved read traffic to a replica and added a cache in front of it.",
      "Then we batched the writes. Same throughput, a third of the connections.",
    ],
    // Optional: one media array per tweet, same length as thread_tweets.
    thread_media: [[], [], []],
    publish_now: true,
  }),
});

const post = await res.json();
console.log(post);

One call, one thread

is_thread plus thread_tweets is all you need. OpenTweet chains the tweets into a reply thread in order. thread_media is optional and, when present, must have one array per tweet.
3

Schedule the thread for later

Want the thread to go out at a specific time? Swap publish_now for scheduled_date, an ISO 8601 timestamp like 2026-07-10T09:00:00Z. publish_now and scheduled_date are mutually exclusive, so send only one of them. Omit both and the thread is saved as a draft you can publish or schedule whenever you like.

bash
curl -X POST https://opentweet.io/api/v1/posts \
  -H "Authorization: Bearer ot_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "is_thread": true,
    "thread_tweets": [
      "How we cut our API latency by 60%. A thread.",
      "First, we moved read traffic to a replica and added a cache in front of it.",
      "Then we batched the writes. Same throughput, a third of the connections."
    ],
    "scheduled_date": "2026-07-10T09:00:00Z"
  }'

publish_now and scheduled_date are mutually exclusive

Send only one. scheduled_date takes an ISO 8601 timestamp like 2026-07-10T09:00:00Z. Omit both fields to save the thread as a draft instead.
4

Verify the thread is queued

Confirm the thread landed where you expect with GET /posts?status=scheduled. The response lists your queued posts with their scheduled times and post ids. Use the id to update or cancel the thread later, or to line it up in a batch schedule of up to 50 posts via POST /posts/batch-schedule.

bash
curl https://opentweet.io/api/v1/posts?status=scheduled \
  -H "Authorization: Bearer ot_your_key"

Need to line up several threads at once? Save each as a draft, then send their post ids to POST /posts/batch-schedule (up to 50 per call) to set every time in one request.

5

Or post it from an MCP client

If your workflow runs through Claude Code, Cursor, Windsurf, ChatGPT, or OpenClaw, skip the HTTP entirely. Connect OpenTweet's MCP server, hosted at mcp.opentweet.io/mcp or run locally with npx, and call the opentweet_create_thread tool. Describe the thread in natural language and the agent posts it. It is one of 36 tools in the server.

Local MCP server

mcp config
{
  "mcpServers": {
    "opentweet": {
      "command": "npx",
      "args": ["-y", "@opentweet/mcp-server"],
      "env": {
        "OPENTWEET_API_KEY": "ot_your_key"
      }
    }
  }
}

Hosted MCP endpoint

mcp config
{
  "mcpServers": {
    "opentweet": {
      "url": "https://mcp.opentweet.io/mcp",
      "transport": "streamable-http",
      "headers": {
        "Authorization": "Bearer ot_your_key"
      }
    }
  }
}

opentweet_create_thread

Once connected, tell your agent to post a thread and it calls opentweet_create_thread for you. It is one of 36 OpenTweet MCP tools. See the full list on the Twitter MCP Server page.

Thread Fields at a Glance

Required for a thread

  • is_thread: true marks the post as a thread
  • thread_tweets: array of strings, one per tweet
  • Authorization: Bearer ot_your_key on every request
  • Base URL https://opentweet.io/api/v1

Optional timing and media

  • publish_now: true posts the thread immediately
  • scheduled_date: ISO 8601 time (exclusive with publish_now)
  • thread_media: one array per tweet, aligned to thread_tweets
  • Omit publish_now and scheduled_date to save a draft

Pro Tips for Threads via API

Keep thread_media aligned

When you use thread_media, it must line up one to one with thread_tweets. If your thread has three tweets, thread_media should have three arrays, even if some are empty like [[], [], []]. This keeps images attached to the right tweet and avoids a shifted thread.

Draft first, then batch-schedule

Omit both publish_now and scheduled_date to save a thread as a draft, then line up several drafts with POST /posts/batch-schedule (up to 50 at once). This is the clean way to plan a week of threads and set every time in a single call.

Verify the key before you script

Run GET /me with your key before wiring it into a job. A quick 200 response confirms the ot_ key is valid and active, so a failed thread later is about the payload, not auth.

Let an agent write and post

The opentweet_create_thread MCP tool means an AI agent can both draft the thread and post it. Pair it with opentweet_get_best_times to pick a slot, then schedule the whole thing without a single line of HTTP.

Common Mistakes to Avoid

Using api.opentweet.io

There is no api.opentweet.io host. The REST base URL is https://opentweet.io/api/v1. Point your thread POST at opentweet.io/api/v1/posts, not a subdomain, or the request will fail to resolve.

Sending publish_now and scheduled_date together

These two fields are mutually exclusive. Send publish_now: true to post now, or scheduled_date to schedule, never both. If you want a draft, omit both fields and publish the thread later.

Posting each tweet separately

You do not need a loop that POSTs one tweet at a time and stitches replies. Pass the full thread_tweets array in one call. Manual chaining risks broken replies and hits rate limits that OpenTweet already handles for you.

Forgetting the Bearer prefix

The Authorization header must read Authorization: Bearer ot_your_key. Dropping the Bearer keyword or the ot_ prefix returns an auth error. Verify with GET /me if a thread request comes back unauthorized.

Prefer the Command Line?

The OpenTweet CLI wraps the same API. Install it, authenticate once, and post or schedule from your terminal.

Install and post

bash
npm install -g @opentweet/cli
opentweet auth
opentweet tweet "Shipping something new today." --now
opentweet tweet "Reminder at 9am." --schedule "2026-07-10 09:00"

Frequently Asked Questions

How do I post a Twitter thread via API?

Send one POST request to https://opentweet.io/api/v1/posts with is_thread set to true and thread_tweets as an array of strings, one string per tweet. Add publish_now: true to post right away, or scheduled_date to schedule it. Include your key as Authorization: Bearer ot_your_key. OpenTweet chains the tweets into a proper reply thread for you.

Do I need a separate call for each tweet in the thread?

No. The entire thread is one request. You pass every tweet in the thread_tweets array and OpenTweet handles the replies and ordering. You do not manage in_reply_to ids or rate limits yourself.

Can I attach images to a thread via the API?

Yes. Pass thread_media, an array with one entry per tweet, in the same order as thread_tweets. For example thread_media: [[], [], []] gives no media on any of three tweets, while putting media into a slot attaches it to that tweet. Leave thread_media out entirely for a text-only thread.

How do I schedule a thread instead of posting it now?

Replace publish_now with scheduled_date, an ISO 8601 timestamp like 2026-07-10T09:00:00Z. publish_now and scheduled_date are mutually exclusive, so send only one. Omit both to save the thread as a draft you can publish later.

What base URL should I use?

The REST base URL is https://opentweet.io/api/v1. There is no api.opentweet.io host, so do not use one. Every endpoint, including POST /posts for threads, lives under https://opentweet.io/api/v1.

Can an AI agent post threads without writing HTTP?

Yes. OpenTweet ships an MCP server with 36 tools. Point Claude Code, Cursor, Windsurf, ChatGPT, or OpenClaw at the hosted endpoint https://mcp.opentweet.io/mcp or run it locally with npx -y @opentweet/mcp-server, then call opentweet_create_thread. The agent posts the thread by describing it in natural language.

Post Your First Thread via API

One bearer key, one call. No X developer account. Free 7-day trial.