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
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.curl https://opentweet.io/api/v1/me \
-H "Authorization: Bearer ot_your_key"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
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
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.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.
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.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.
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.
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
{
"mcpServers": {
"opentweet": {
"command": "npx",
"args": ["-y", "@opentweet/mcp-server"],
"env": {
"OPENTWEET_API_KEY": "ot_your_key"
}
}
}
}Hosted MCP endpoint
{
"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
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.
Keep exploring
OpenTweet vs the X API
Post, schedule, and automate X without a developer account or the $200/mo minimum.
Post to X without an API
The clean, account-safe way to post to X from your code or an AI agent.
Twitter MCP Server
Give Claude, Cursor, and OpenClaw the ability to post to X. 36 tools included.
Developer docs
Quickstart, API keys, MCP setup, and the REST reference for posting to X from code or an agent.
XMCP vs OpenTweet
X's official MCP server bills per API call and cannot schedule. Compare it with the flat-fee hosted MCP.
MCP for AI agents
Connect your AI client to X in under two minutes, no X developer account.
Developer API and keys
REST endpoints, one bearer key, and usage tracking. Build on OpenTweet.
OpenTweet for AI agents
The posting layer for autonomous agents and automations that live on X.
Build an AI Twitter persona
Give your AI agent its own X account. Setup, cadence, and the rules that keep it safe.
Post Your First Thread via API
One bearer key, one call. No X developer account. Free 7-day trial.