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.
/api/v1/threadsCreate or schedule a thread/api/v1/threads/:idGet thread details and per-platform status/api/v1/threads/:idUpdate a draft or scheduled thread/api/v1/threads/:idCancel or delete a threadThere 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
/api/v1/threadsCreate or schedule a threadCreate 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
| Name | Type | Required | Description |
|---|---|---|---|
Authorization | string | Required | Bearer token. Example: Bearer sk_live_abc123... |
Content-Type | string | Required | Must be application/json |
Idempotency-Key | string | Optional | Unique key to prevent duplicate threads. Recommended. |
AuthorizationstringRequiredBearer token. Example: Bearer sk_live_abc123...
Content-TypestringRequiredMust be application/json
Idempotency-KeystringOptionalUnique key to prevent duplicate threads. Recommended.
Request body
| Name | Type | Required | Description |
|---|---|---|---|
platforms | array | Required | Array of platform targets (twitter, threads, bluesky, mastodon). Strings, or objects with platform and optional accountId. |
posts | array | Required | 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 | object | Optional | Thread-wide per-platform options keyed by platform name, e.g. { mastodon: { visibility: "unlisted" } }. |
publishNow | boolean | Optional | Publish the whole thread immediately instead of scheduling. |
scheduledFor | string | Optional | ISO 8601 date for scheduling. Must be at least 5 minutes in the future. |
timezone | string | Optional | IANA timezone string (e.g. "America/New_York"). |
config | object | Optional | Accepted for backward compatibility. See config parameters below. |
firstComment | string | Optional | Auto-post this text as a comment on the ROOT entry after the thread publishes (shorthand for firstComments: [{target: 0, text}]). |
firstComments | array | Optional | 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. |
platformsarrayRequiredArray of platform targets (twitter, threads, bluesky, mastodon). Strings, or objects with platform and optional accountId.
postsarrayRequiredOrdered 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).
platformSettingsobjectOptionalThread-wide per-platform options keyed by platform name, e.g. { mastodon: { visibility: "unlisted" } }.
publishNowbooleanOptionalPublish the whole thread immediately instead of scheduling.
scheduledForstringOptionalISO 8601 date for scheduling. Must be at least 5 minutes in the future.
timezonestringOptionalIANA timezone string (e.g. "America/New_York").
configobjectOptionalAccepted for backward compatibility. See config parameters below.
firstCommentstringOptionalAuto-post this text as a comment on the ROOT entry after the thread publishes (shorthand for firstComments: [{target: 0, text}]).
firstCommentsarrayOptionalAuto-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
| Name | Type | Required | Description |
|---|---|---|---|
content | string | Optional | Text for this entry. |
mediaItems | array | Optional | At most ONE media item per entry ({ type, url }). Extra items are rejected with a 400. |
platformContent | object | Optional | Per-platform text override for this entry, keyed by platform (e.g. { twitter: "..." }). Falls back to content. |
contentstringOptionalText for this entry.
mediaItemsarrayOptionalAt most ONE media item per entry ({ type, url }). Extra items are rejected with a 400.
platformContentobjectOptionalPer-platform text override for this entry, keyed by platform (e.g. { twitter: "..." }). Falls back to content.
Config parameters
| Name | Type | Required | Description |
|---|---|---|---|
postDelay | number | Optional | Accepted but NOT honored — the delay between entries is fixed per platform (see the note above). |
continueOnError | boolean | Optional | Stored on the thread for contract stability.Default: false |
maxRetries | number | Optional | Stored on the thread for contract stability.Default: 3 |
postDelaynumberOptionalAccepted but NOT honored — the delay between entries is fixed per platform (see the note above).
continueOnErrorbooleanOptionalStored on the thread for contract stability.
Default: false
maxRetriesnumberOptionalStored 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
/api/v1/threads/:idGet thread details and per-platform statusRetrieve 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
| Name | Type | Required | Description |
|---|---|---|---|
id | string | Required | The thread ID (e.g. thread_xyz123). |
idstringRequiredThe 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
/api/v1/threads/:idUpdate a draft or scheduled threadReschedule 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
| Name | Type | Required | Description |
|---|---|---|---|
id | string | Required | The thread ID to update. |
idstringRequiredThe thread ID to update.
Request body
| Name | Type | Required | Description |
|---|---|---|---|
scheduledFor | string | Optional | New schedule time (ISO 8601). Reschedules the underlying post; allowed only while it is draft or scheduled. |
config | object | Optional | Merge updates into the thread config. |
title | string | Optional | Set a human-readable thread title. |
scheduledForstringOptionalNew schedule time (ISO 8601). Reschedules the underlying post; allowed only while it is draft or scheduled.
configobjectOptionalMerge updates into the thread config.
titlestringOptionalSet 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
/api/v1/threads/:idCancel or delete a threadCancel 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
| Name | Type | Required | Description |
|---|---|---|---|
id | string | Required | The thread ID to cancel. |
idstringRequiredThe 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"}