Publishing
Threads, Replies and Quotes
Publish a thread of replies, reply to an existing post, or quote one on X, Threads and Bluesky.
Publish a post with a chain of replies under it, publish a post as a reply to another post, or quote a post. These work on X, Threads and Bluesky.
| Platform | thread | replyToPostId | quotePostId |
|---|---|---|---|
| X (Twitter) | No. Use Comments | ||
| Threads | |||
| Bluesky |
| Field | Where | Effect |
|---|---|---|
thread | Request body | Publishes each item as a reply under the first post, in order |
replyToPostId | Platform options, threads or bluesky | Publishes the post as a reply to an existing post |
quotePostId | Platform options, x, threads or bluesky | Quotes an existing post |
Publish a Thread
Add thread to a Create Post request. The top-level text, mediaKind and media make up the first post, and each thread item is one reply under it.
import { Configuration, PostsApi } from "@onepostly/sdk";
const postsApi = new PostsApi(
new Configuration({ accessToken: process.env.ONEPOSTLY_API_KEY })
);
const response = await postsApi.createPost({
createPostBody: {
"text": "Three things we shipped this month.",
"thread": [
{
"text": "1. Scheduling in any IANA time zone."
},
{
"text": "2. Remote delete for whole threads."
},
{
"text": "3. Webhooks for posts made outside Onepostly."
}
],
"accounts": [
{
"accountId": "acc_YOUR_X_ACCOUNT_ID"
},
{
"accountId": "acc_YOUR_THREADS_ACCOUNT_ID"
}
]
},
});
console.log(response);{
"groupId": "grp_7d2e5b1a9c4f4a68b3e07f1c2d9a6e45",
"data": [
{
"id": "pst_3c8a2d6e91b44f7a8e250d6b4c1f9a73",
"groupId": "grp_7d2e5b1a9c4f4a68b3e07f1c2d9a6e45",
"accountId": "acc_YOUR_X_ACCOUNT_ID",
"platform": "x",
"source": "onepostly",
"status": "publishing",
"text": "Three things we shipped this month.",
"mediaKind": "text",
"media": [],
"thread": [
{
"text": "1. Scheduling in any IANA time zone.",
"media": []
},
{
"text": "2. Remote delete for whole threads.",
"media": []
},
{
"text": "3. Webhooks for posts made outside Onepostly.",
"media": []
}
],
"scheduledFor": null,
"timezone": null,
"options": {},
"platformPostId": null,
"url": null,
"error": null,
"publishedAt": null,
"metrics": null,
"createdAt": "2027-03-15T09:00:00.000Z",
"updatedAt": "2027-03-15T09:00:00.000Z"
},
{
"id": "pst_3c8a2d6e91b44f7a8e250d6b4c1f9a02",
"groupId": "grp_7d2e5b1a9c4f4a68b3e07f1c2d9a6e45",
"accountId": "acc_YOUR_THREADS_ACCOUNT_ID",
"platform": "threads",
"source": "onepostly",
"status": "publishing",
"text": "Three things we shipped this month.",
"mediaKind": "text",
"media": [],
"thread": [
{
"text": "1. Scheduling in any IANA time zone.",
"media": []
},
{
"text": "2. Remote delete for whole threads.",
"media": []
},
{
"text": "3. Webhooks for posts made outside Onepostly.",
"media": []
}
],
"scheduledFor": null,
"timezone": null,
"options": {},
"platformPostId": null,
"url": null,
"error": null,
"publishedAt": null,
"metrics": null,
"createdAt": "2027-03-15T09:00:00.000Z",
"updatedAt": "2027-03-15T09:00:00.000Z"
}
]
}| Rule | Detail |
|---|---|
| Length | 1 to 25 items |
| Each item | text and up to 20 media files, given as id or url like the post's own media. An item needs text or media |
| First post | Needs text or media |
| Text limits | Each item's text has to fit every account of the request |
| Per account | Thread items cannot be set per account. Every account publishes the same replies |
| Platforms | Every account of the request has to be on X, Threads or Bluesky. Otherwise the request returns 400 VALIDATION_ERROR |
Each platform limits the media of one reply, such as 4 images on X. The limits are in each platform's Media Requirements section.
The post returns its replies in thread, and has one id for the whole thread.
- On X, each post of the thread is charged from the wallet. See X Wallet.
- Deleting the post deletes every post of the thread. See Delete a Post.
- If a reply fails after earlier posts went live, the post ends as
failed. See Threads That Fail Partway. - To change the thread of a scheduled post, send the whole new
threadwith Edit a Scheduled Post.
Reply to a Post
Set replyToPostId in the account's threads or bluesky options. The post publishes as a reply to that post.
import { Configuration, PostsApi } from "@onepostly/sdk";
const postsApi = new PostsApi(
new Configuration({ accessToken: process.env.ONEPOSTLY_API_KEY })
);
const response = await postsApi.createPost({
createPostBody: {
"text": "Here is how we set this up.",
"accounts": [
{
"accountId": "acc_YOUR_THREADS_ACCOUNT_ID",
"threads": {
"replyToPostId": "pst_3c8a2d6e91b44f7a8e250d6b4c1f9a73"
}
}
]
},
});
console.log(response);{
"groupId": "grp_7d2e5b1a9c4f4a68b3e07f1c2d9a6e02",
"data": [
{
"id": "pst_3c8a2d6e91b44f7a8e250d6b4c1f9a02",
"groupId": "grp_7d2e5b1a9c4f4a68b3e07f1c2d9a6e02",
"accountId": "acc_YOUR_THREADS_ACCOUNT_ID",
"platform": "threads",
"source": "onepostly",
"status": "publishing",
"text": "Here is how we set this up.",
"mediaKind": "text",
"media": [],
"thread": [],
"scheduledFor": null,
"timezone": null,
"options": {
"threads": {
"replyToPostId": "18047285913046723"
}
},
"platformPostId": null,
"url": null,
"error": null,
"publishedAt": null,
"metrics": null,
"createdAt": "2027-03-15T09:00:00.000Z",
"updatedAt": "2027-03-15T09:00:00.000Z"
}
]
}On X, a reply to a post is a comment. Use Comment on a Post instead.
Quote a Post
Set quotePostId in the account's x, threads or bluesky options. The post publishes with the quoted post embedded.
import { Configuration, PostsApi } from "@onepostly/sdk";
const postsApi = new PostsApi(
new Configuration({ accessToken: process.env.ONEPOSTLY_API_KEY })
);
const response = await postsApi.createPost({
createPostBody: {
"text": "Worth reading if you run scheduled jobs.",
"accounts": [
{
"accountId": "acc_YOUR_X_ACCOUNT_ID",
"x": {
"quotePostId": "1960956321831854280"
}
}
]
},
});
console.log(response);{
"groupId": "grp_7d2e5b1a9c4f4a68b3e07f1c2d9a6e45",
"data": [
{
"id": "pst_3c8a2d6e91b44f7a8e250d6b4c1f9a73",
"groupId": "grp_7d2e5b1a9c4f4a68b3e07f1c2d9a6e45",
"accountId": "acc_YOUR_X_ACCOUNT_ID",
"platform": "x",
"source": "onepostly",
"status": "publishing",
"text": "Worth reading if you run scheduled jobs.",
"mediaKind": "text",
"media": [],
"thread": [],
"scheduledFor": null,
"timezone": null,
"options": {
"x": {
"quotePostId": "1960956321831854280"
}
},
"platformPostId": null,
"url": null,
"error": null,
"publishedAt": null,
"metrics": null,
"createdAt": "2027-03-15T09:00:00.000Z",
"updatedAt": "2027-03-15T09:00:00.000Z"
}
]
}Post References
replyToPostId and quotePostId name the post in one of two ways.
| Value | Example | Rule |
|---|---|---|
A pst_ id | pst_3c8a2d6e91b44f7a8e250d6b4c1f9a73 | A post of this workspace that is live on the same platform. Posts made outside Onepostly work too, once a sync found them |
| The platform's own id | 1960956321831854280 | The numeric post id on X and Threads, or the at:// URI on Bluesky. Use it for posts of other accounts. The platform decides whether the account can reply to or quote the post |
- A
pst_id of a post on another platform returns400 VALIDATION_ERROR. - A
pst_id of a post that is not live, such as ascheduledorfailedpost, returns409 POST_NOT_PUBLISHED. Wait forpost.published, or use the platform's own id. - A platform id is sent to the platform as it is. If the platform cannot find the post, the post fails when it publishes, with the code in
error.
Platform Differences
Media per reply, text limits and the codes each platform returns are on its page.
- X. Replies to existing posts go through Comments.
- Threads.
- Bluesky. A Bluesky reference has to be an
at://URI or apst_id.
Errors
| Code | HTTP | Cause | Fix |
|---|---|---|---|
VALIDATION_ERROR | 400 | A thread item is empty, an account's platform has no threads, or a pst_ reference is on another platform | Fix the field named in param or error |
INSUFFICIENT_WALLET | 402 | The wallet does not cover every post of an X thread | Top up the wallet. See X Wallet |
POST_NOT_PUBLISHED | 409 | quotePostId or replyToPostId names a pst_ post that is not live | Wait for post.published, or use the platform's own post id |
INVALID_QUOTE, INVALID_REPLY | Post error | The Bluesky post to quote or reply to is not a valid at:// URI, or could not be found | Use the pst_ id or at:// URI of an existing post |
Every other code is in Errors.