Threads API

Create and schedule multi-post threads (also known as tweetstorms or thread posts). Threads are ordered sequences of posts published as a connected series on supported platforms.

Supported platforms: Threads are currently supported on Twitter, Threads (Meta), Bluesky, and Mastodon. Other platforms do not have native thread/reply-chain support.

How threads publish: the whole chain is created from a single scheduled job, so the entire thread reads or cancels as one unit and returns a single postId. The delay between entries is fixed per platform (about 1s on Twitter, ~1.5s on Bluesky and Mastodon, and ~30s on Threads, since Meta requires each post to finish processing before the next reply). config.postDelay is accepted for backward compatibility but is not honored. If a later entry fails and the job is retried, earlier entries can be re-posted (duplicated) — keep threads short and idempotent.

POST/api/v1/threadsCreate or schedule a thread
GET/api/v1/threads/:idGet thread details and per-platform status
PATCH/api/v1/threads/:idUpdate a draft or scheduled thread
DELETE/api/v1/threads/:idCancel or delete a thread

There is no list endpoint for threads yet. Store the thread.id returned when you create a thread, then use it to read, update, or cancel that thread.

Create a thread

POST/api/v1/threadsCreate or schedule a thread

Create a multi-post thread that will be published as a connected sequence. Each post in the thread is published in order, with replies chained to the previous post. You can configure the delay between posts and error handling behavior.

Headers

Authorization
stringRequired

Bearer token. Example: Bearer sk_live_abc123...

Content-Type
stringRequired

Must be application/json

Idempotency-Key
stringOptional

Unique key to prevent duplicate threads. Recommended.

Request body

platforms
arrayRequired

Array of platform targets (twitter, threads, bluesky, mastodon). Strings, or objects with platform and optional accountId.

posts
arrayRequired

Ordered array of 2-25 thread entries. Each entry may include content (string), mediaItems (at most ONE media object with type and url per entry), and platformContent (per-platform text override for that entry).

platformSettings
objectOptional

Thread-wide per-platform options keyed by platform name, e.g. { mastodon: { visibility: "unlisted" } }.

publishNow
booleanOptional

Publish the whole thread immediately instead of scheduling.

scheduledFor
stringOptional

ISO 8601 date for scheduling. Must be at least 5 minutes in the future.

timezone
stringOptional

IANA timezone string (e.g. "America/New_York").

config
objectOptional

Accepted for backward compatibility. See config parameters below.

firstComment
stringOptional

Auto-post this text as a comment on the ROOT entry after the thread publishes (shorthand for firstComments: [{target: 0, text}]).

firstComments
arrayOptional

Auto-posted comments per thread entry ([{target, text}]): target 0 = entry 1 (the root), target i = entry i+1, max target = number of entries - 1. Thread-targeted comments (target > 0) deliver on twitter/threads/bluesky only; mastodon takes only the target-0 comment. Delivery status appears in platforms[].firstComments on GET /api/v1/posts/:id.

Per-entry fields

content
stringOptional

Text for this entry.

mediaItems
arrayOptional

At most ONE media item per entry ({ type, url }). Extra items are rejected with a 400.

platformContent
objectOptional

Per-platform text override for this entry, keyed by platform (e.g. { twitter: "..." }). Falls back to content.

Config parameters

postDelay
numberOptional

Accepted but NOT honored — the delay between entries is fixed per platform (see the note above).

continueOnError
booleanOptional

Stored on the thread for contract stability.

Default: false

maxRetries
numberOptional

Stored on the thread for contract stability.

Default: 3

curl -X POST https://schedulala.com/api/v1/threads \
-H "Authorization: Bearer sk_live_abc123..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: thread_$(uuidgen)" \
-d '{
"platforms": [
{ "platform": "twitter", "accountId": "acc_twitter_123" },
{ "platform": "bluesky", "accountId": "acc_bluesky_456" }
],
"posts": [
{
"content": "1/ We just launched something big. Here is what we built and why it matters. A thread."
},
{
"content": "2/ The problem: most social media tools make you copy-paste the same content everywhere. But each platform is different.",
"mediaItems": [
{ "type": "image", "url": "https://example.com/problem-diagram.jpg" }
]
},
{
"content": "3/ Our solution: one API call, tailored content per platform, automatic scheduling. Try it free at schedulala.com"
}
],
"scheduledFor": "2026-03-15T14:00:00Z",
"timezone": "America/New_York",
"config": {
"postDelay": 3,
"continueOnError": true
}
}'
{
"success": true,
"thread": {
"id": "665f0a1b2c3d4e5f60718293",
"title": null,
"platforms": [
"twitter",
"bluesky"
],
"status": "scheduled",
"scheduledFor": "2026-03-15T14:00:00.000Z",
"postId": "665e0a1b2c3d4e5f60718200",
"entryCount": 3,
"posts": [
{
"postId": "665e0a1b2c3d4e5f60718200",
"position": 1,
"status": "pending"
},
{
"postId": "665e0a1b2c3d4e5f60718200",
"position": 2,
"status": "pending"
},
{
"postId": "665e0a1b2c3d4e5f60718200",
"position": 3,
"status": "pending"
}
],
"config": {
"postDelay": 3000,
"continueOnError": false,
"maxRetries": 3
},
"isApiPost": true,
"createdAt": "2026-03-01T12:00:00.000Z",
"updatedAt": "2026-03-01T12:00:00.000Z"
}
}

The whole chain publishes from one post, so every entry shares the same postId. Poll GET /api/v1/posts/{postId} (or the thread endpoint below) for live status.

Get thread details

GET/api/v1/threads/:idGet thread details and per-platform status

Retrieve full details for a thread. The status is reconciled from the underlying post on every read (so it never stays stuck on processing). Each entry shares the single postId; once published, per-entry platformPostIds (with the live post id and url) are attached where the platform reports them.

Path parameters

id
stringRequired

The thread ID (e.g. thread_xyz123).

curl https://schedulala.com/api/v1/threads/thread_xyz123 \
-H "Authorization: Bearer sk_live_abc123..."
{
"success": true,
"thread": {
"id": "665f0a1b2c3d4e5f60718293",
"title": null,
"platforms": [
"twitter",
"bluesky"
],
"status": "posted",
"scheduledFor": "2026-03-15T14:00:00.000Z",
"postId": "665e0a1b2c3d4e5f60718200",
"entryCount": 3,
"posts": [
{
"postId": "665e0a1b2c3d4e5f60718200",
"position": 1,
"status": "posted",
"platformPostIds": {
"twitter": {
"postId": "1897654321098765432",
"url": "https://x.com/yourhandle/status/1897654321098765432"
},
"bluesky": {
"postId": "bafyabc123",
"url": "https://bsky.app/profile/yourhandle.bsky.social/post/abc123"
}
}
},
{
"postId": "665e0a1b2c3d4e5f60718200",
"position": 2,
"status": "posted",
"platformPostIds": {
"twitter": {
"postId": "1897654321098765433",
"url": "https://x.com/yourhandle/status/1897654321098765433"
}
}
},
{
"postId": "665e0a1b2c3d4e5f60718200",
"position": 3,
"status": "posted",
"platformPostIds": {
"twitter": {
"postId": "1897654321098765434",
"url": "https://x.com/yourhandle/status/1897654321098765434"
}
}
}
],
"config": {
"postDelay": 3000,
"continueOnError": false,
"maxRetries": 3
},
"isApiPost": true,
"createdAt": "2026-03-01T12:00:00.000Z",
"updatedAt": "2026-03-15T14:00:15.000Z"
}
}

Only Threads and Mastodon report a distinct id/url for every entry; on Twitter and Bluesky only the first entry carries the reported id, so later positions omit platformPostIds.

Update a thread

PATCH/api/v1/threads/:idUpdate a draft or scheduled thread

Reschedule a thread whose underlying post is still draft or scheduled. Publishing, posted, failed, and cancelled threads cannot be rescheduled. Only include the fields you want to change. To change the entries themselves, cancel the thread and create a new one.

Path parameters

id
stringRequired

The thread ID to update.

Request body

scheduledFor
stringOptional

New schedule time (ISO 8601). Reschedules the underlying post; allowed only while it is draft or scheduled.

config
objectOptional

Merge updates into the thread config.

title
stringOptional

Set a human-readable thread title.

curl -X PATCH https://schedulala.com/api/v1/threads/665f0a1b2c3d4e5f60718293 \
-H "Authorization: Bearer sk_live_abc123..." \
-H "Content-Type: application/json" \
-d '{
"scheduledFor": "2026-03-16T10:00:00Z",
"title": "Launch thread"
}'
{
"success": true,
"thread": {
"id": "665f0a1b2c3d4e5f60718293",
"title": "Launch thread",
"platforms": [
"twitter",
"bluesky"
],
"status": "scheduled",
"scheduledFor": "2026-03-16T10:00:00.000Z",
"postId": "665e0a1b2c3d4e5f60718200",
"entryCount": 3,
"posts": [
{
"postId": "665e0a1b2c3d4e5f60718200",
"position": 1,
"status": "pending"
},
{
"postId": "665e0a1b2c3d4e5f60718200",
"position": 2,
"status": "pending"
},
{
"postId": "665e0a1b2c3d4e5f60718200",
"position": 3,
"status": "pending"
}
],
"config": {
"postDelay": 3000,
"continueOnError": false,
"maxRetries": 3
},
"isApiPost": true,
"createdAt": "2026-03-01T12:00:00.000Z",
"updatedAt": "2026-03-01T15:00:00.000Z"
}
}

Delete a thread

DELETE/api/v1/threads/:idCancel or delete a thread

Cancel a scheduled or draft thread. The thread status is set to cancelled and none of its posts will be published. Already-published threads cannot be deleted through this endpoint.

Path parameters

id
stringRequired

The thread ID to cancel.

curl -X DELETE https://schedulala.com/api/v1/threads/665f0a1b2c3d4e5f60718293 \
-H "Authorization: Bearer sk_live_abc123..."

A scheduled thread is cancelled (its post and every platform entry flip to cancelled) and returns method: "cancelled". A draft thread is hard-deleted (thread and post both removed) with no method field.

{
"success": true,
"deleted": true,
"id": "665f0a1b2c3d4e5f60718293",
"method": "cancelled"
}

Related