ChirpieDocs
API Reference

Comments

List the comments on a post you published, reply to one, hide it, or delete it.

What can I do with comments?

For a post Chirpie published, you can list the comments it received, reply to one, hide one, and delete one, on the platforms that allow each of those. Comments are read from a stored snapshot that Chirpie refreshes on a schedule, so a listing is fast and costs you nothing beyond your plan's monthly sync allowance.

GET    /api/v1/posts/:id/comments
POST   /api/v1/posts/:id/comments/:comment_id/reply
POST   /api/v1/posts/:id/comments/:comment_id/hide
DELETE /api/v1/posts/:id/comments/:comment_id

Every route takes Authorization: Bearer chirpie_sk_YOUR_KEY. The :id is Chirpie's own post id, the one every Posts API response carries, and :comment_id is the id of a comment from the listing.

A reply is a post. It is published to the platform like any other post, so it counts as one post against your monthly quota. Hiding and deleting cost nothing.

Which platforms support which actions?

PlatformListReplyHideDelete
X/TwitterYesYesNoYour own replies
BlueskyYesYesNoYour own replies
MastodonYesYesNoYour own replies
LinkedIn (Page) (Coming Soon)YesYesNoYour own comments
LinkedIn (profile)NoNoNoNo
Facebook (Coming Soon)YesYesYesAny comment
Instagram (Coming Soon)YesYesYesAny comment
Threads (Coming Soon)YesYesYesYour own replies
TelegramNoNoNoNo

Every listing carries the same table for the post you asked about, in meta.capabilities, so you never have to hard-code it:

"capabilities": { "reply": true, "hide": true, "delete_own": true, "delete_any": true }

delete_own and delete_any are separate because on most platforms you may only delete replies you wrote. Offer a Delete control on a stranger's comment only when delete_any is true.

An action the platform does not have returns 501 comment_action_unsupported with a sentence naming what it does allow. It never returns success for something that did not happen.


List Comments

GET /api/v1/posts/:id/comments
Authorization: Bearer chirpie_sk_YOUR_KEY

Query Parameters

ParameterTypeDefaultDescription
limitinteger25Comments per page (max 100)
cursorstringNoneThe next_cursor from the previous page
sincestring (ISO 8601)NoneOnly comments posted after this time
syncstringautoauto refreshes when the platform's refresh window has passed, true asks for a refresh now (honoured a minute after the last one, 15 minutes on X), false never refreshes
include_hiddenbooleanfalseInclude comments you have hidden. They carry hidden: true
include_deletedbooleanfalseInclude comments that are gone from the platform. They carry deleted: true and keep their text
parent_idstringNoneOnly the replies to this comment. Takes the comment's platform_comment_id, not its Chirpie id

Response 200 OK

{
  "data": [
    {
      "id": "6f1c2d3e-4a5b-6c7d-8e9f-0a1b2c3d4e5f",
      "post_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "platform": "facebook",
      "platform_comment_id": "1234_5678",
      "platform_parent_id": null,
      "author": {
        "handle": "@someone",
        "display_name": "Someone",
        "platform_id": "9876",
        "avatar_url": null
      },
      "text": "Does this work with n8n?",
      "created_at": "2026-09-18T10:02:11.000Z",
      "likes": 3,
      "replies": 1,
      "hidden": false,
      "deleted": false,
      "own": false,
      "replied": true,
      "replied_at": "2026-09-18T10:09:40.000Z",
      "reply_comment_id": "7a2d3e4f-5b6c-7d8e-9f0a-1b2c3d4e5f60"
    }
  ],
  "meta": {
    "next_cursor": "MjAyNi0wOS0xOFQxMDowMjoxMVp8MTIzNF81Njc4",
    "capabilities": { "reply": true, "hide": true, "delete_own": true, "delete_any": true },
    "sync": {
      "status": "ok",
      "synced_at": "2026-09-18T10:10:00.000Z",
      "reason": null,
      "next_sync_after": "2026-09-18T10:11:00.000Z"
    }
  }
}

replied is Chirpie's own record that you answered this comment, and reply_comment_id points at the reply. It survives a handle change and a reply made outside Chirpie, which is why it is a field rather than something you work out from the author. If the reply it points at is deleted, replied goes back to false.

own is true for anything the connected account wrote, your replies and first comments included, and their author is the connected account: its name, handle, id and avatar.

A comment with deleted: true keeps text exactly as Chirpie last stored it. Once the platform has removed a comment, that is the only copy left, so it is returned rather than blanked. hidden and deleted are independent: a comment can be both.

Pagination

Comments come back newest first. Page by passing the previous response's meta.next_cursor back as cursor, and stop when next_cursor is null. The cursor is opaque: do not parse it or build one yourself.

curl "https://chirpie.ai/api/v1/posts/POST_ID/comments?limit=50" \
  -H "Authorization: Bearer chirpie_sk_YOUR_KEY"

curl "https://chirpie.ai/api/v1/posts/POST_ID/comments?limit=50&cursor=MjAyNi0..." \
  -H "Authorization: Bearer chirpie_sk_YOUR_KEY"

The sync object

A listing always answers from Chirpie's stored snapshot, and meta.sync says how fresh that snapshot is and why.

statusMeaning
okThe snapshot is current
unsupportedThe platform exposes no comment read for this post
permissionThe connection needs re-authorizing. reason says what to do
rate_limitedThe platform is rate limiting. The snapshot is returned as it stands
budgetYour plan's monthly comment allowance is spent
planYour plan does not include comment syncing for this platform
errorThe last refresh failed. The snapshot is returned as it stands

reason carries a short sentence for any status but ok, already worded for your users. next_sync_after is the earliest moment a sync=true will be honoured.

How often does a listing refresh?

Two windows apply, both per post. An ordinary listing (sync=auto) refreshes once the platform's refresh window has passed since the last sync. An explicit sync=true waits a shorter window, because it is someone asking for the latest comments on purpose.

Platformsync=autosync=true
X/Twitter15 minutes15 minutes
Facebook, Instagram, Threads, LinkedIn (Page)5 minutes1 minute
Bluesky, Mastodon2 minutes1 minute

X keeps its 15-minute window on sync=true too. Every X refresh spends your plan's X comment read allowance, which is counted per reply X returns, so a shorter window there would spend it faster without showing much more. A refresh that failed waits longer than either window, doubling on each consecutive failure up to an hour, or as long as the platform's own Retry-After when it names one; next_sync_after says when.

sync=true is a request, not a guarantee. A refresh that arrives inside the sync=true window for that platform is skipped and the snapshot answers as it stands, with sync.status: "ok" and next_sync_after naming the earliest moment another refresh will be attempted. A refresh refused by your plan's allowance, by the platform, or by a connection that needs re-authorizing answers from the snapshot with sync.status of budget, plan, rate_limited or permission. Either way it is a 200, not an error: the read succeeded.

The one exception is a sync=true on a post with no stored comments at all. There is no snapshot to answer with, and an empty 200 would read as "this post has no comments", so the refusal is returned instead: 402 comment_read_budget_exceeded, 429 comment_sync_rate_limited or 409 comment_permission_required, carrying the sentence that would otherwise have been in sync.reason.


Reply to a Comment

POST /api/v1/posts/:id/comments/:comment_id/reply
Authorization: Bearer chirpie_sk_YOUR_KEY
Content-Type: application/json

Request Body

FieldTypeRequiredDescription
textstringYesThe reply. Same per-platform character limits as a post
curl -X POST https://chirpie.ai/api/v1/posts/POST_ID/comments/COMMENT_ID/reply \
  -H "Authorization: Bearer chirpie_sk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "text": "Yes, pass schedule_at and we will queue it." }'

Response 201 Created

The reply, in the same shape as a listed comment, with own: true. The comment it answers comes back from the next listing with replied: true.

A reply counts as one post against your monthly quota, and an X reply whose text contains a link carries the same X link-post charge a normal X post does.


Hide a Comment

POST /api/v1/posts/:id/comments/:comment_id/hide
Authorization: Bearer chirpie_sk_YOUR_KEY
Content-Type: application/json
FieldTypeRequiredDescription
hiddenbooleanYestrue hides the comment, false shows it again

Response 200 OK

The whole comment comes back, with hidden set to what you asked for, so you can render the updated row without listing again.

{ "data": { "id": "6f1c2d3e-...", "hidden": true, "...": "every other comment field" } }

A hidden comment stays in Chirpie's listing when you pass include_hidden=true, so your own moderation history is never lost even though the platform stops returning it.

Only Facebook, Instagram and Threads have a hide. Everywhere else this returns 501 comment_action_unsupported.


Delete a Comment

DELETE /api/v1/posts/:id/comments/:comment_id
Authorization: Bearer chirpie_sk_YOUR_KEY

Response 200 OK

{ "data": { "id": "6f1c2d3e-...", "deleted": true } }

On Facebook and Instagram you can delete any comment on a post you published. Everywhere else you can delete only replies you wrote, and deleting someone else's returns 501 comment_action_unsupported. Check meta.capabilities.delete_any before offering the control.

The comment is kept in Chirpie with deleted: true and its text, and comes back with include_deleted=true, so a deletion is recorded rather than erased. Deleting the same comment again answers the same 200, so a retry is safe.

What happens to the replies

Some platforms delete a comment's replies along with it. Chirpie records those as deleted too, so the thread matches what is on the platform:

PlatformReplies under a deleted comment
FacebookDeleted with it
InstagramDeleted with it
ThreadsDeleted with it
LinkedIn (Page)Deleted with it
X/TwitterStay live
BlueskyStay live
MastodonStay live

The same applies when a comment is deleted on the platform itself: the next sync records the comment and, on the first four platforms, the replies under it as deleted.


How many comment syncs do I get?

One sync is one refresh of one post, whatever it costs upstream. Listings from the snapshot are unlimited.

PlanComment syncs/moX comment reads/mo
Free200Not included
Agent1,000500
Starter5,0002,000
Pro25,00010,000
ScaleCustomCustom
EnterpriseUnlimitedUnlimited

X is metered a second way because X bills per object returned: an X comment read unit is one reply X handed back. X accounts connected with your own X API credentials are exempt from the X read allowance, and you pay X directly.

On the Free plan, a listing for an X post answers from the snapshot with sync.status: "plan". It is a 200 with an explanation, not an error. See Rate Limits for the full table.


Error Responses

StatusCodeCondition
400bad_requestA missing or malformed field, or an unrecognised query value
400validation_errorA reply with no text, or text over the target platform's character limit
402comment_read_budget_exceededYour plan's monthly comment allowance is spent and there is no snapshot to answer with
402x_link_posts_require_paid_planAn X reply containing a link, from a Free-plan account
404not_foundThe post or the comment does not exist, or belongs to another user
409comment_permission_requiredThe connection needs re-authorizing, and on a listing only when you asked for sync=true and there is no snapshot to answer with. Reconnect the account from the dashboard
429comment_sync_rate_limitedThe platform is rate limiting and there is no snapshot to answer with. Retry after Retry-After
429usage_limit_exceededYour monthly post quota is spent, and a reply is published as a post
429rate_limitedThe burst limit on your API key
501comments_unsupportedThe platform exposes no comment read for this post
501comment_action_unsupportedThe platform allows reading but not this action
501platform_coming_soonThe platform is recognised but not available yet
502upstream_errorThe platform refused the reply, hide or delete. Nothing changed

See Error Codes for the full reference.

On this page