DocumentationPost a thread
How to post a thread on X, Threads, Bluesky or Mastodon
A thread is a post followed by more posts that continue it. BuzzTake publishes the whole thread in one post action: the first post goes in text and the others in thread, in order.
You need a BuzzTake API key and an active account on X, Threads, Bluesky or Mastodon.
1. Check that the platform has threads
| Platform | Threads | Notes |
|---|---|---|
| X | Yes | Media goes on the first post only. |
| Threads | Yes | Each part is at most 500 characters. |
| Bluesky | Yes | Each part is at most 300 characters. |
| Mastodon | Yes | Each part replies to the one before. Later parts carry no media and use the default visibility. |
| Facebook, LinkedIn, Reddit | No | The action fails with invalid_input. Post once, then reply to your own post. |
| Instagram, TikTok, YouTube, Pinterest, Telegram | No | thread is ignored and only the first post goes out. |
2. Split the text into parts
BuzzTake does not split or shorten text. thread holds up to 25 parts after the first post, and no part may be empty. Check each part against the platform's limit before you send it:
JavaScript
// Paragraphs become parts. Check each part against the platform's limit.
const draft = `BuzzTake posts threads now.
Send the first post in text and the rest in thread.
One action, one charge.`;
const [text, ...thread] = draft.split(/\n\s*\n/).map((part) => part.trim()).filter(Boolean);
const LIMIT = 300; // Bluesky
const tooLong = [text, ...thread].filter((part) => [...part].length > LIMIT);
if (tooLong.length > 0) throw new Error(`${tooLong.length} part(s) over ${LIMIT} characters`);
if (thread.length > 25) throw new Error("A thread takes at most 25 more parts.");Python
# Paragraphs become parts. Check each part against the platform's limit.
draft = """BuzzTake posts threads now.
Send the first post in text and the rest in thread.
One action, one charge."""
parts = [part.strip() for part in draft.split("\n\n") if part.strip()]
text, thread = parts[0], parts[1:]
LIMIT = 300 # Bluesky
too_long = [part for part in parts if len(part) > LIMIT]
if too_long:
raise SystemExit(f"{len(too_long)} part(s) over {LIMIT} characters")
if len(thread) > 25:
raise SystemExit("A thread takes at most 25 more parts.")3. Post the thread
POST/v1/accounts/{id}/actions
Send type: "post" with text and thread. Add media to put photos or videos on the first post. A thread takes longer than one post, so give wait more time, up to 120 seconds.
curl
curl https://api.buzztake.com/v1/accounts/$ACCOUNT_ID/actions \
-H "Authorization: Bearer $BUZZTAKE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: thread-launch-1" \
-d '{
"type": "post",
"text": "BuzzTake posts threads now.",
"thread": [
"Send the first post in text and the rest in thread.",
"One action, one charge."
],
"wait": 90
}'JavaScript
const res = await fetch(
`https://api.buzztake.com/v1/accounts/${process.env.ACCOUNT_ID}/actions`,
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.BUZZTAKE_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": "thread-launch-1",
},
body: JSON.stringify({ type: "post", text, thread, wait: 90 }),
},
);
if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
const action = await res.json();
console.log(action.status, action.result?.url ?? action.error?.message ?? "");Python
import os
import requests
resp = requests.post(
f"https://api.buzztake.com/v1/accounts/{os.environ['ACCOUNT_ID']}/actions",
headers={
"Authorization": f"Bearer {os.environ['BUZZTAKE_API_KEY']}",
"Idempotency-Key": "thread-launch-1",
},
json={"type": "post", "text": text, "thread": thread, "wait": 90},
timeout=100,
)
if not resp.ok:
raise SystemExit(f"{resp.status_code}: {resp.text}")
action = resp.json()
print(action["status"], (action.get("result") or {}).get("url") or action.get("error"))The whole thread is one action and costs 10 credits, the price of one post. Over MCP, call the post tool with the same text and thread.
4. Read the result
{
"type": "post",
"status": "succeeded",
"params": {
"text": "BuzzTake posts threads now.",
"thread": ["Send the first post in text and the rest in thread.", "One action, one charge."]
},
"result": { "type": "created", "url": "https://bsky.app/profile/acme.bsky.social/post/3l...", "id": "3l..." },
"credits": 10
}result is created, with the url and id the platform gives the new thread. If the action is still running when the wait ends, you get 202; read it again with GET /v1/actions/{id}?wait=60. Do not send the post again: the first request is still working.
5. Post the same thread from several accounts
The batch route takes thread like any other parameter. Every account gets the same parts, so keep each part within the smallest limit in the batch: 300 characters when a Bluesky account is in it.
POST/v1/workspaces/{workspace_id}/actions
curl https://api.buzztake.com/v1/workspaces/$WORKSPACE_ID/actions \
-H "Authorization: Bearer $BUZZTAKE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: thread-launch-all-1" \
-d '{
"account_ids": ["0199a1b2-...", "0199b2c3-...", "0199c3d4-..."],
"type": "post",
"text": "BuzzTake posts threads now.",
"thread": ["Send the first post in text and the rest in thread.", "One action, one charge."],
"wait": 90
}'Common errors
- 422 invalid_input
- "
threaditems must not be empty" - 422 invalid_input
- "
threadhas more than 25 items" - Action error invalid_input
- "invalid input: Bluesky posts are limited to 300 characters", or the same for Threads at 500. Nothing was posted and the credits are refunded. Shorten the part and post again with a new
Idempotency-Key. - Action error invalid_input
- "invalid input: LinkedIn has no threads; post once and comment instead". Facebook and Reddit refuse a thread the same way.
See also
- The post action
- X for AI agents
- How to post to many social media accounts at once
- How to read and reply to comments on your posts
- How to retry API calls without posting twice
To run this on your own accounts, create a BuzzTake account, then add an account and an API key.