Guides
Comments and inbox
Receive comments and direct messages, answer them, and keep inside the platforms' reply rules.
How comments reach you
- Facebook and Instagram send us a notification when a comment is made, and we pass it on as a
comment.createdwebhook event. This is the main path: subscribe to it. See Webhooks. - LinkedIn has no notifications for organic content, so we poll it. Comments appear after the next poll, not instantly.
- Sync on demand.
POST /v1/accounts/{accountId}/comments/syncreads the account's recent posts and their comments now. Use it to catch up after your webhook endpoint was down, or to refresh LinkedIn straight away. New and changed comments still send their normal events.
{ "account_id": "0192a7c1-6a10-7b22-8e31-4c5d6e7f8a01", "posts_seen": 20, "comments_created": 3, "comments_updated": 1 }A sync that is already running for the account returns 409 invalid_state. The account needs the comments capability, or you get 400 unsupported_for_platform.
Warning Instagram comment management is not available yet. Instagram accounts report comments: false and comment_hide: false, and the comment endpoints return 400 unsupported_for_platform for them. Facebook comments, Instagram publishing and Instagram direct messages work as normal. Platform notes explains the reconnect that will be needed once it is released.
Read comments
GET /v1/comments?account_id=…&post_id=…&status=VISIBLEFilters: account_id, post_id, external_post_id, parent_id, since, is_own and status (VISIBLE, HIDDEN, DELETED). since filters on when we stored the comment, which is also the order of the pages. GET /v1/comments/{commentId} returns one comment with replies_count.
A comment looks like this:
{
"id": "0192a7c3-2a00-7e55-9c66-7d8e9fa0b001",
"account_id": "0192a7c1-6a10-7b22-8e31-4c5d6e7f8a01",
"platform": "FACEBOOK_PAGE",
"post_id": "0192a7c2-1f00-7c33-9a44-5b6c7d8e9f01",
"parent_id": null,
"author": { "external_id": "7744558899001122", "type": "PERSON", "name": "Jane Doe", "avatar_url": "https://…" },
"text": "Is the pumpkin latte available with oat milk?",
"permalink": "https://www.facebook.com/104857600123456/posts/998877665544332?comment_id=112233445566",
"is_own": false,
"status": "VISIBLE",
"replies_count": 2
}post_idisnullwhen the post was not published through WaSparks.author.nameandauthor.avatar_urlcan benull. For LinkedIn people they are alwaysnull: LinkedIn does not allow storing profile data of other members.author.typeisPERSON,ORGANIZATIONorUNKNOWN. Show a neutral label such as "LinkedIn member" and link topermalink.- For LinkedIn organizations the name is filled in shortly after the comment arrives, and a
comment.updatedevent follows. permalinklinks to the comment on the platform, so a person can always see who wrote it.
Reply, hide, react, delete
| To | Call | Works on |
|---|---|---|
| Reply | POST /v1/comments/{commentId}/replies with { "text": "…" } |
Facebook, Instagram, LinkedIn |
| Comment on a post | POST /v1/posts/{postId}/targets/{targetId}/comments |
Published posts |
| Hide / unhide | POST /v1/comments/{commentId}/hide and …/unhide |
Facebook, Instagram |
| React | POST /v1/comments/{commentId}/reactions with { "type": "LIKE" }, remove with DELETE |
Facebook Pages, LinkedIn organizations |
| Delete | DELETE /v1/comments/{commentId} |
Where the platform allows it |
curl -X POST https://connect.social.wasparks.com/v1/comments/0192a7c3-2a00-7e55-9c66-7d8e9fa0b001/replies \
-H "Authorization: Bearer $WASPARKS_KEY" -H "X-Tenant-Id: acme-001" \
-H "Idempotency-Key: 0c8e2d3a-5f4b-4a1e-9d7c-1b2a3c4d5e6f" \
-H "Content-Type: application/json" \
-d '{"text": "Yes, every latte comes with oat milk on request."}'
const res = await fetch(`https://connect.social.wasparks.com/v1/comments/${commentId}/replies`, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.WASPARKS_KEY}`,
"X-Tenant-Id": "acme-001",
"Idempotency-Key": crypto.randomUUID(),
"Content-Type": "application/json",
},
body: JSON.stringify({ text: "Yes, every latte comes with oat milk on request." }),
});
const reply = await res.json();
import os, uuid, requests
r = requests.post(
f"https://connect.social.wasparks.com/v1/comments/{comment_id}/replies",
headers={
"Authorization": f"Bearer {os.environ['WASPARKS_KEY']}",
"X-Tenant-Id": "acme-001",
"Idempotency-Key": str(uuid.uuid4()),
},
json={"text": "Yes, every latte comes with oat milk on request."},
)
reply = r.json()Rules to know:
- Instagram allows replies to top-level comments only. A reply to an Instagram reply returns
400 unsupported_for_platform. - LinkedIn cannot hide or unhide comments (
400 unsupported_for_platform), and LinkedIn profiles have no comment access. - Hide, unhide and delete return the updated comment with
statusHIDDEN,VISIBLEorDELETED. Acting on a deleted comment gives409 invalid_state. - Reactions and deletes that succeed with nothing to return answer
204. 422 platform_rejectedmeans the platform refused; its reason is inerror.details.- Send an
Idempotency-Keyon replies so a retry does not post twice.
Conversations (Messenger and Instagram DM)
LinkedIn has no messaging API, so conversations exist for Facebook Pages (MESSENGER) and Instagram accounts (INSTAGRAM_DM) with capabilities.messaging.
| To | Call |
|---|---|
| List threads | GET /v1/conversations (filters: account_id, channel, status, unread, since; newest activity first) |
| Read a thread | GET /v1/conversations/{conversationId} |
| Read messages | GET /v1/conversations/{conversationId}/messages (newest first, with a cursor) |
| Send | POST /v1/conversations/{conversationId}/messages with { "text": "…" }, a media_id, or both |
| Mark read, close, reopen | POST …/read, …/close, …/reopen |
close and reopen set the thread's inbox state in WaSparks only. Nothing changes on the platform.
The 24-hour window
Meta only lets you send a message within 24 hours of the person's last message. Each conversation says where it stands:
"reply_window": {
"open": true,
"closes_at": "2026-11-03T09:00:00Z",
"human_agent_until": "2026-11-09T09:00:00Z"
}- Sending outside the window returns
422 reply_window_closed. Checkreply_window.openfirst. - With
"tag": "HUMAN_AGENT"a message can be sent up to 7 days after the person's last message. This needs Meta's Human Agent permission to be enabled for the app.human_agent_untilisnullwhen it is not available, and sending the tag then fails with400 validation_failed. closes_atis our best estimate. Meta does not publish the exact time, so the platform's own refusal (reply_window_closed) is the final answer.
Message delivery
A sent message is accepted as QUEUED, and message.sent or message.failed follows. Its status moves through QUEUED, SENT, DELIVERED, READ or FAILED. Read receipts say that everything before a time was read, so READ can appear on several messages at once.
If we never learn the outcome of a send, the message becomes FAILED with the error code send_outcome_unknown, which means it may or may not have arrived. Look at the conversation on the platform before you send it again.
Next: Webhooks