Overview
Comments and Engagement
Endpoints for reading and writing comments, likes, reposts, bookmarks and quotes, with the webhooks each action sends.
Read and reply to comments, moderate them, and like, repost, bookmark or quote posts from your connected accounts. Every endpoint targets its post with post, accountId or destinationId, described in Targeting a Post.
Support by Platform
| Platform | List and reply to comments | Delete own comment | Hide comment | Like comment | Private reply | Like post | Repost and quote | Bookmark |
|---|---|---|---|---|---|---|---|---|
| X | Yes | Yes | No | No | No | Yes | Yes | Yes |
| Yes | Yes | Yes | No | Yes | No | No | No | |
| Yes | Yes | Yes | Yes | Yes | Yes | No | No | |
| Threads | Yes | Yes | Yes | No | No | No | Yes | No |
| YouTube | Yes | Yes | No | No | No | Yes | No | No |
| Bluesky | Yes | Yes | No | No | No | Yes | Yes | Yes |
| No | No | No | No | No | No | No | No | |
| TikTok | No | No | No | No | No | No | No | No |
| No | No | No | No | No | No | No | No |
Calling an action a platform does not support returns UNSUPPORTED_PLATFORM. Platform specifics are on each platform's Engagement page, for example X.
On X, write actions are billed to your wallet like other X usage. When the wallet is empty they return INSUFFICIENT_WALLET.
Comments
List Comments
GET /v1/comments returns one entry in subjects per destination, each with its comments, nextCursor and error. Replies are nested under their parent in replies.
Prop
Type
import { Configuration, CommentsApi } from "@onepostly/sdk";
const commentsApi = new CommentsApi(
new Configuration({ apiKey: process.env.ONEPOSTLY_API_KEY })
);
const response = await commentsApi.listComments({
post: "1699f415-7fb6-43f4-9d2a-c447491f32a8",
limit: 25,
});
console.log(response);{
"comments": {
"post": "1699f415-7fb6-43f4-9d2a-c447491f32a8",
"subjects": [
{
"scope": "destination",
"subjectId": "d4e5f6a7-8b9c-4d0e-8f1a-2b3c4d5e6f7a",
"accountId": "a1b2c3d4-e5f6-4a7b-8c9d-e0f1a2b3c4d5",
"platform": "instagram",
"externalPostId": "17895695668004550",
"status": "ready",
"comments": [
{
"id": "c1",
"text": "Love this!",
"username": "jane_doe",
"likeCount": 12,
"timestamp": "2026-08-25T10:05:00.000Z",
"parentId": null
}
],
"nextCursor": null,
"error": null
}
]
}
}Reply to a Post or Comment
POST /v1/comments publishes a comment from the account that owns the targeted destination. Returns 201 with the new comment.
Prop
Type
import { Configuration, CommentsApi } from "@onepostly/sdk";
const commentsApi = new CommentsApi(
new Configuration({ apiKey: process.env.ONEPOSTLY_API_KEY })
);
const response = await commentsApi.createComment({
createCommentBody: {
"post": "1699f415-7fb6-43f4-9d2a-c447491f32a8",
"text": "Thanks for watching!",
"parentCommentId": "17858893269000001",
"accountId": "YOUR_INSTAGRAM_ACCOUNT_ID"
},
});
console.log(response);{
"comment": {
"id": "c1",
"text": "Love this!",
"username": "jane_doe",
"likeCount": 12,
"timestamp": "2026-08-25T10:05:00.000Z"
}
}Delete a Comment
DELETE /v1/comments deletes a comment your account wrote. Pass the selector and commentId as query parameters.
import { Configuration, CommentsApi } from "@onepostly/sdk";
const commentsApi = new CommentsApi(
new Configuration({ apiKey: process.env.ONEPOSTLY_API_KEY })
);
const response = await commentsApi.deleteComment({
post: "1699f415-7fb6-43f4-9d2a-c447491f32a8",
accountId: "YOUR_BLUESKY_ACCOUNT_ID",
commentId: "at://did:plc:abc123/app.bsky.feed.post/3kq2c4x7v2s2a",
});
console.log(response);{
"deleted": {
"postId": "1699f415-7fb6-43f4-9d2a-c447491f32a8",
"destinationId": "d4e5f6a7-8b9c-4d0e-8f1a-2b3c4d5e6f7a",
"platform": "x",
"commentId": "c0",
"deleted": true
}
}On X, Instagram, Facebook and Threads, a commentId that is one of your published posts is refused with NOT_A_COMMENT. Use remote delete for posts.
Hide or Unhide a Comment
POST /v1/comments/hide with commentId and hidden (true to hide, false to unhide).
import { Configuration, CommentsApi } from "@onepostly/sdk";
const commentsApi = new CommentsApi(
new Configuration({ apiKey: process.env.ONEPOSTLY_API_KEY })
);
const response = await commentsApi.hideComment({
body: {
"post": "1699f415-7fb6-43f4-9d2a-c447491f32a8",
"commentId": "122104567890123456_987654321",
"hidden": true,
"accountId": "YOUR_FACEBOOK_ACCOUNT_ID"
},
});
console.log(response);{
"hidden": {
"postId": "string",
"destinationId": "string",
"platform": "string",
"commentId": "string",
"hidden": false
}
}Like a Comment
POST /v1/comments/like with commentId likes a comment. DELETE /v1/comments/like with the same parameters as query parameters removes the like. Facebook only.
import { Configuration, CommentsApi } from "@onepostly/sdk";
const commentsApi = new CommentsApi(
new Configuration({ apiKey: process.env.ONEPOSTLY_API_KEY })
);
const response = await commentsApi.likeComment({
commentTargetBody: {
"post": "1699f415-7fb6-43f4-9d2a-c447491f32a8",
"commentId": "122104567890123456_987654321",
"accountId": "YOUR_FACEBOOK_ACCOUNT_ID"
},
});
console.log(response);{
"liked": {
"postId": "string",
"destinationId": "string",
"platform": "string",
"commentId": "string",
"liked": false
}
}Send a Private Reply
POST /v1/comments/private-reply sends a direct message to the person who wrote commentId. text is up to 2,000 characters. Instagram and Facebook only; details are on the Instagram and Facebook pages.
import { Configuration, CommentsApi } from "@onepostly/sdk";
const commentsApi = new CommentsApi(
new Configuration({ apiKey: process.env.ONEPOSTLY_API_KEY })
);
const response = await commentsApi.createPrivateReply({
body: {
"post": "1699f415-7fb6-43f4-9d2a-c447491f32a8",
"commentId": "17858893269000001",
"text": "Thanks! Check your DMs.",
"accountId": "YOUR_INSTAGRAM_ACCOUNT_ID"
},
});
console.log(response);{
"reply": {
"postId": "string",
"destinationId": "string",
"platform": "string",
"commentId": "string",
"reply": {
"id": "string",
"text": "string",
"timestamp": "string"
}
}
}Likes, Reposts, and Bookmarks
All of these take only the selector. Create with POST (selector in the body, returns 201), undo with DELETE (selector as query parameters, returns 200).
| Action | Create | Undo | Response fields |
|---|---|---|---|
| Like a post | POST /v1/likes | DELETE /v1/likes | kind: "like", active |
| Bookmark a post | POST /v1/bookmarks | DELETE /v1/bookmarks | kind: "bookmark", active |
| Repost | POST /v1/retweets | DELETE /v1/retweets | retweeted, retweetId |
Each response also contains postId, destinationId and platform. The repost endpoints are named /v1/retweets on every platform.
import { Configuration, EngagementApi } from "@onepostly/sdk";
const engagementApi = new EngagementApi(
new Configuration({ apiKey: process.env.ONEPOSTLY_API_KEY })
);
const response = await engagementApi.like({
engagementTargetBody: {
"post": "1960956321831854280",
"accountId": "YOUR_X_ACCOUNT_ID"
},
});
console.log(response);{
"postId": "1699f415-7fb6-43f4-9d2a-c447491f32a8",
"destinationId": "d4e5f6a7-8b9c-4d0e-8f1a-2b3c4d5e6f7a",
"platform": "x",
"kind": "like",
"active": true
}List Reposts
GET /v1/retweets lists the accounts that reposted a post, in subjects[].actors, with limit (1 to 100, default 25) and cursor. Available on X and Bluesky.
import { Configuration, EngagementApi } from "@onepostly/sdk";
const engagementApi = new EngagementApi(
new Configuration({ apiKey: process.env.ONEPOSTLY_API_KEY })
);
const response = await engagementApi.listRetweeters({
post: "3kq2c4x7v2s2a",
accountId: "YOUR_BLUESKY_ACCOUNT_ID",
limit: 25,
});
console.log(response);{
"retweets": {
"post": "1699f415-7fb6-43f4-9d2a-c447491f32a8",
"subjects": [
{
"scope": "destination",
"subjectId": "d4e5f6a7-8b9c-4d0e-8f1a-2b3c4d5e6f7a",
"accountId": "a1b2c3d4-e5f6-4a7b-8c9d-e0f1a2b3c4d5",
"platform": "x",
"externalPostId": "1960956321831854280",
"status": "ready",
"actors": [
{
"id": "u1",
"username": "jane_doe",
"displayName": "Jane Doe",
"avatarUrl": "https://cdn.onepostly.com/avatars/jane.jpg"
}
],
"nextCursor": null
}
]
}
}Quote a Post
POST /v1/quotes with the selector and text publishes a new post from the same account that quotes the targeted post. Available on X, Threads and Bluesky. The response contains sourcePostId, sourceDestinationId and the new post. To quote while creating a regular post, see Threads and Quotes.
import { Configuration, EngagementApi } from "@onepostly/sdk";
const engagementApi = new EngagementApi(
new Configuration({ apiKey: process.env.ONEPOSTLY_API_KEY })
);
const response = await engagementApi.quote({
quoteBody: {
"post": "1699f415-7fb6-43f4-9d2a-c447491f32a8",
"text": "Worth a read",
"accountId": "YOUR_THREADS_ACCOUNT_ID"
},
});
console.log(response);{
"sourcePostId": "1699f415-7fb6-43f4-9d2a-c447491f32a8",
"sourceDestinationId": "d4e5f6a7-8b9c-4d0e-8f1a-2b3c4d5e6f7a",
"post": {
"id": "b3e1a7c2-8f4d-4e6a-9c1b-2d3e4f5a6b7c",
"text": "Worth a read",
"mediaUrls": [
"https://cdn.onepostly.com/media/product.jpg"
],
"mediaKind": "image",
"status": "queued",
"scheduledFor": null,
"timezone": null,
"destinations": [
{
"id": "d4e5f6a7-8b9c-4d0e-8f1a-2b3c4d5e6f7a",
"accountId": "a1b2c3d4-e5f6-4a7b-8c9d-e0f1a2b3c4d5",
"platform": "x",
"status": "draft",
"externalPostId": "17895695668004550",
"externalUrl": "https://x.com/you/status/17895695668004550",
"errorCode": null,
"errorMessage": null,
"publishedAt": "2026-08-25T10:00:00.000Z",
"metrics": null
}
],
"createdAt": "2026-08-25T10:00:00.000Z",
"updatedAt": "2026-08-25T10:00:00.000Z"
}
}Webhooks
| Action | Webhook event |
|---|---|
Reply with POST /v1/comments | comment.created |
Delete with DELETE /v1/comments | comment.deleted |
| New comment on an Instagram or Facebook post | comment.received |
| Like or unlike a post | engagement.liked, engagement.unliked |
| Bookmark or remove a bookmark | engagement.bookmarked, engagement.unbookmarked |
| Repost or undo a repost | engagement.retweeted, engagement.unretweeted |
| Quote a post | engagement.quoted and post.platform.published |
Except comment.received, these events fire only for actions you take through the API, not for other people's likes or reposts. Hiding, liking a comment and private replies send no webhook. Payloads are in Comment Events and Engagement Events.
Errors
Selector errors (ACCOUNT_REQUIRED, NOT_PUBLISHED, AMBIGUOUS_TARGET and others) are listed in Targeting a Post.
| Code | Cause | Fix |
|---|---|---|
UNSUPPORTED_PLATFORM | The platform does not support this action through Onepostly. | Check Support by Platform. |
VALIDATION_ERROR | A required field such as commentId or text is missing. | Send the required fields. |
TEXT_TOO_LONG | text exceeds the platform's limit. | Shorten the text to the Text Limits. |
NOT_A_COMMENT | commentId is one of your published posts. | Delete the post with remote delete. |
INSUFFICIENT_WALLET | An X action needs wallet balance. | Top up the wallet, then try again. |
CONNECTION_INACTIVE | The account is disconnected or needs reconnecting. | Reconnect the account. |
TOKEN_INVALID | The platform rejected the account's authorization. | Reconnect the account. |
PERMISSION_DENIED | The account lacks the permission for this action. | Reconnect and grant all requested permissions. |
COMMENT_CREATE_FAILED, COMMENT_DELETE_FAILED, COMMENT_HIDE_FAILED, COMMENT_LIKE_FAILED, COMMENT_UNLIKE_FAILED, PRIVATE_REPLY_FAILED, ENGAGEMENT_FAILED, RETWEET_FAILED, UNRETWEET_FAILED, QUOTE_FAILED | The platform refused the action without a specific reason. | Read message, then try again later. |
A 429 response means a rate limit was reached; see Handle 429 Responses.