Put ThreadMaster inside your own workflow
A REST API for everything the app does: generate threads with AI, publish or schedule them to X, Threads and Facebook Pages, read the results, and get signed webhooks when posts go live. Built for scripts, Make, n8n and Zapier.
Included with every ThreadMaster subscription. Keys are created in Settings → Developer API.
curl -X POST https://threadmaster.ai/api/public/v1/threads/generate/ \
-H "Authorization: Bearer tm_live_…" \
-H "Content-Type: application/json" \
-d '{"topic": "5 lessons from shipping a side project", "style": "default"}'What you can automate
Every capability of the app, with the same guardrails.
Generate threads
Same AI writer as the app, with styles, formats, CTAs and your saved Writing DNA. Returns the thread and its suggested X split.
Publish to X
Post now, schedule for a time, or drop it in your queue. Cancel, reschedule, retry and read per-post results.
Threads & Facebook Pages
Publish to Meta Threads as a reply chain, or to a Facebook Page as one post or a comment chain.
Read results
List threads and posts with cursor pagination and a since filter, plus likes, impressions and other metrics over time.
Webhooks
Signed HTTPS callbacks when a thread is generated or a post is scheduled, published, partially published, fails or is cancelled.
Same rules as the app
Your subscription, X posting quota, duplicate guard and daily platform caps apply. Nothing happens through the API that could not happen in the app.
Quickstart
Base URL https://threadmaster.ai/api/public/v1 · JSON in, JSON out · Bearer API keys
1. Create an API key
In the app go to Settings → Developer API, name the key and copy it. Keys look like tm_live_… and are shown once.
2. Check who you are
curl https://threadmaster.ai/api/public/v1/me/ \
-H "Authorization: Bearer tm_live_…"3. Generate a thread
curl -X POST https://threadmaster.ai/api/public/v1/threads/generate/ \
-H "Authorization: Bearer tm_live_…" \
-H "Content-Type: application/json" \
-d '{"topic": "5 lessons from shipping a side project", "style": "default"}'4. Publish it to X (or schedule it)
curl -X POST https://threadmaster.ai/api/public/v1/x/posts/ \
-H "Authorization: Bearer tm_live_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6f1c1e2a-0d0a-4a7f-9d2c-0d5c7f0d2c11" \
-d '{"thread_id": 1234, "scheduled_for": "2026-09-08T14:00:00Z"}'Publishing calls run synchronously and return the final result — allow ~60 seconds for long threads. Send an Idempotency-Key (any UUID) so a retried request replays the original job instead of posting twice.
Endpoints
Full request and response shapes are in the API reference.
Account
| GET | /me/ | The user, key and subscription behind the request |
| GET | /accounts/ | Connected X, Threads and Facebook Page accounts |
| GET | /quota/ | X posting quota standing |
Threads (drafts)
| POST | /threads/generate/ | Generate a thread with AI |
| POST | /threads/ | Create a thread you wrote yourself |
| GET | /threads/ | List threads — ?since, ?status, ?favorite, ?cursor, ?limit |
| GET | /threads/{id}/ | One thread with its publish history |
| PATCH | /threads/{id}/ | Edit content, topic or favourite |
| DELETE | /threads/{id}/ | Delete (409 once it has publish history) |
| GET | /threads/{id}/x/preview/ | How it would split into X posts |
X
| POST | /x/posts/ | Publish now, at scheduled_for, or queue: true |
| GET | /x/posts/ | List X posts |
| GET | /x/posts/{id}/ | One X post with per-tweet results |
| POST | /x/posts/{id}/cancel/ | Cancel a scheduled post |
| POST | /x/posts/{id}/reschedule/ | Move a scheduled post |
| POST | /x/posts/{id}/retry/ | Retry a failed or partial post |
| GET | /x/posts/{id}/metrics/ | Likes, impressions, replies… over time |
Meta Threads
| POST | /threads-app/posts/ | Publish a thread to Threads |
| GET | /threads-app/posts/ | List Threads posts |
| GET | /threads-app/posts/{id}/ | One Threads post |
| POST | /threads-app/posts/{id}/retry/ | Retry |
| GET | /threads-app/posts/{id}/metrics/ | Views, likes, replies… over time |
Facebook Pages
| GET | /facebook/pages/ | Pages you can publish to |
| POST | /facebook/posts/ | Publish to a Page (mode single or comments) |
| GET | /facebook/posts/ | List Facebook posts |
| GET | /facebook/posts/{id}/ | One Facebook post |
| POST | /facebook/posts/{id}/retry/ | Retry |
| GET | /facebook/posts/{id}/metrics/ | Reactions, comments, shares over time |
Webhooks
| GET | /webhooks/ | Your endpoints |
| POST | /webhooks/ | Subscribe a URL to events (secret returned once) |
| PATCH | /webhooks/{id}/ | Change URL, events, pause or re-enable |
| DELETE | /webhooks/{id}/ | Unsubscribe |
| POST | /webhooks/{id}/test/ | Send a test event |
| POST | /webhooks/{id}/rotate-secret/ | Rotate the signing secret (24h overlap) |
| GET | /webhooks/{id}/deliveries/ | Delivery log with responses and retries |
| GET | /events/ | Recent event payloads (sample data for integrations) |
Webhooks
Subscribe a URL in Settings or via the API. We POST a signed JSON envelope and retry for ~33 hours.
Events
thread.generated | A thread was generated (app or API) |
post.scheduled | A post was scheduled or queued |
post.rescheduled | A scheduled post was moved |
post.published | Every part of the post went live |
post.partially_published | Some parts went live, some failed |
post.failed | Nothing went live |
post.cancelled | A scheduled post was cancelled |
Envelope
{
"id": "0f2c6d5e-…",
"type": "post.published",
"api_version": "v1",
"created_at": "2026-09-08T14:00:07Z",
"data": {
"id": 512, "platform": "x", "thread_id": 1234, "status": "posted",
"permalink": "https://x.com/you/status/18…", "n_posts": 5, "posted_count": 5,
"items": [{ "position": 0, "status": "posted", "tweet_id": "18…", "text": "…" }],
"metrics": { "likes": 0, "impressions": 0, "updated_at": null }
}
}Verify the signature
Each request carries ThreadMaster-Timestamp and ThreadMaster-Signature: v1=…, an HMAC-SHA256 of <timestamp>.<raw body> with your endpoint secret. Reject anything older than five minutes. Respond with any 2xx within 10 seconds; anything else is retried with backoff (1m, 5m, 30m, 2h, 6h, 24h) and the endpoint is paused after 20 consecutive failures.
import hashlib, hmac, time
def verify(secret: str, headers, body: bytes, tolerance=300) -> bool:
ts = headers["ThreadMaster-Timestamp"]
if abs(time.time() - int(ts)) > tolerance:
return False
expected = "v1=" + hmac.new(secret.encode(), f"{ts}.".encode() + body,
hashlib.sha256).hexdigest()
# Two values appear for 24h after a secret rotation.
return any(hmac.compare_digest(sig.strip(), expected)
for sig in headers["ThreadMaster-Signature"].split(","))import { createHmac, timingSafeEqual } from "node:crypto";
export function verify(secret, headers, rawBody, tolerance = 300) {
const ts = headers["threadmaster-timestamp"];
if (Math.abs(Date.now() / 1000 - Number(ts)) > tolerance) return false;
const expected = "v1=" + createHmac("sha256", secret)
.update(`${ts}.`).update(rawBody).digest("hex");
return headers["threadmaster-signature"].split(",").some((sig) => {
const a = Buffer.from(sig.trim()), b = Buffer.from(expected);
return a.length === b.length && timingSafeEqual(a, b);
});
}Errors
Every error is {"error": {"code", "message", "details"}}.
400 | invalid_request | Validation failed — details lists the fields |
401 | authentication_required / invalid_api_key | Missing, malformed, revoked or expired key |
402 | subscription_required | The account has no active subscription |
403 | forbidden_scope | The key lacks the scope for this endpoint |
404 | not_found / feature_disabled | Unknown id, or the platform is not enabled for the account |
409 | account_not_connected / duplicate_content / conflict | Connect the social account first; identical content within 72h; state does not allow the action |
429 | rate_limited / quota_exhausted | Throttled (see Retry-After) or out of X posting quota |
502 | generation_failed | The AI provider could not generate — retry |
Rate limits
| Per key | 60 requests/minute, 5,000/day |
| AI generation | 30/hour and 200/day per account (all keys combined) |
| Publishing | 30/hour per account, plus your plan's X posting quota |
| Headers | X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset; Retry-After on 429 |
Zapier & Make
Make and n8n work today with the HTTP module and a Bearer key. A native Zapier app is on the roadmap; the webhook subscribe/unsubscribe endpoints and the since filters are already REST-hook and polling friendly.
Write your next social media thread today
Sign up in under a minute. $9 a month, cancel anytime.