Comments API Threading, mentions, reactions, and reference anchoring for workspace and share entities.

Base URL: https://api.fast.io/current/ Auth: Bearer {jwt_token} Content-Type: application/json Format: JSON

Comments use JSON request bodies (Content-Type: application/json), unlike most other Fastio endpoints which use application/x-www-form-urlencoded.


Endpoint Summary

MethodEndpointDescription
GET /current/comments/{entity_type}/{parent_id}/ List all comments in a workspace or share
GET /current/comments/{entity_type}/{parent_id}/{node_id}/ List comments for a specific node
POST /current/comments/{entity_type}/{parent_id}/ Create or update a comment on an entity
POST /current/comments/{entity_type}/{parent_id}/{node_id}/ Create or update a comment on a node
GET /current/comments/fileshare/{fileshare_id}/{node_id}/ List a File Share recipient's comments on a node
POST /current/comments/fileshare/{fileshare_id}/{node_id}/ Create or update a comment as a File Share recipient
POST /current/comments/{comment_id}/update/ Edit a comment by ID (works for every comment surface)
GET /current/comments/{comment_id}/details/ Get a single comment's details
DELETE /current/comments/{comment_id}/delete/ Soft-delete a comment and its replies
POST /current/comments/bulk/delete/ Bulk soft-delete multiple comments
POST /current/comments/{comment_id}/reactions/ Add or change an emoji reaction
DELETE /current/comments/{comment_id}/reactions/ Remove an emoji reaction
GET /current/comments/{comment_id}/attachments/ List a comment's attachments (hydrated, access-gated)
POST /current/comments/{comment_id}/attachments/ Attach one or many objects to a comment
POST /current/comments/{comment_id}/attachments/detach/ Detach an object from a comment

Searching comments: To search comments by keyword, use the unified search endpoint — GET /current/workspace/{workspace_id}/search/ (or /current/share/{share_id}/search/) returns a comments bucket alongside files and other types, each with its own pagination. See Unified Search in the Storage Operations reference. Comment search results are permission-filtered to comments the caller can see.


Path Parameters

Comments are scoped to a workspace, share, or File Share, and optionally to a specific node (file or folder) within it. When no node ID is specified, all comments across the entire workspace or share are returned.

ParameterTypeFormatDescription
{entity_type} string "workspace", "share", or "fileshare" Entity type discriminator. For "fileshare" the {node_id} segment is required (see File Share Comments).
{parent_id} string 19-digit numeric Workspace, share, or File Share profile ID. Note: Do not confuse with parent_id in the POST request body, which is the parent comment ID for threading.
{node_id} string Alphanumeric opaque ID File or folder ID within the entity (optional for workspace/share, required for fileshare)
{comment_id} string Alphanumeric opaque ID Comment identifier

File Share comments. When {entity_type} is "fileshare", {parent_id} is the File Share's 19-digit numeric profile ID. Comments on a File Share are scoped to that File Share — a recipient sees only the comments made under it, never comments on the same underlying file from the owning workspace or from another File Share. Commenting requires the viewer to be signed in; public anyone-with-link visitors cannot comment. Comments are available only when the File Share owner has enabled comments, and they are always disabled on public anyone-with-link shares. A client should read the File Share's effective comments_enabled flag from its details response to decide whether to show the comment UI.


Comment Object

Every comment returned by the API has this structure:

FieldTypeDescription
id string Alphanumeric opaque ID of the comment
entity string Opaque ID of the entity the comment belongs to (workspace, share, or node)
user_id string|null 19-digit numeric ID of the comment author. null for externally-authored comments (e.g. a File Share recipient) — in that case the external_author_* fields below identify the author
parent_id string|null Opaque ID of the parent comment (for replies), or null for top-level
body string Comment text content (may include mention markup)
profile_type string|null The container type ("workspace" or "share") that owns the entity
profile_id string|null 19-digit numeric ID of the workspace or share that owns the entity
scope_id string|null When a comment originated under a File Share and is surfaced in a workspace context, the 19-digit numeric ID of that File Share — a present (non-null) value marks the comment as "via File Share". Null/omitted for comments that originated directly in the workspace or share
external_author_email string|null Email of an external author (File Share recipient), when the comment was not authored by a member; otherwise omitted/null
external_author_name string|null Display name of the external author, when present; otherwise omitted/null
external_author_token_id string|null Opaque ID of the access token the external author used, when present; otherwise omitted/null
reference object|null Anchoring reference to a position in a file (see Reference Anchoring)
mentions array The server-validated set of mentioned profile IDs that took effect (19-digit numeric strings). Always present; empty when no mention took effect. This is the authoritative took-effect set — mentions in the body markup that fail validation (e.g. a non-member) are excluded here
reactions object Map of emoji character to total reaction count (e.g., {"👍": 3})
user_reaction string|null The current authenticated user's emoji reaction, or null
version_hash string|null Hash representing the current comment content version
version integer Monotonically increasing version counter (starts at 1)
attachment_count integer Number of objects attached to the comment (see Comment Attachments). Present on comment list rows and the comment detail response
attachments array Hydrated, access-gated attachment rows (see Comment Attachments). Detail endpoint only
edited_at string|null Timestamp of last edit if the comment has been edited (YYYY-MM-DD HH:MM:SS UTC), or null
can_edit boolean Whether the requesting user can edit this comment
can_delete boolean Whether the requesting user can delete this comment
can_reply boolean Whether the comment can be replied to (top-level only)
created string Creation timestamp (YYYY-MM-DD HH:MM:SS UTC)
updated string Last-updated timestamp (YYYY-MM-DD HH:MM:SS UTC)
deleted string|null Deletion timestamp (YYYY-MM-DD HH:MM:SS UTC), or null if active. Only included on the get-details endpoint or when explicitly requesting deleted comments.

Note: the server-validated mentions set is surfaced as the top-level mentions array described above. The raw internal properties object (threading, pinning, content-filter flags, etc.) is never returned — only the curated mentions list is exposed.


List Comments

GET /current/comments/{entity_type}/{parent_id}/

List all comments across the entire workspace or share.

GET /current/comments/{entity_type}/{parent_id}/{node_id}/

List comments for a specific node within an entity.

Without {node_id}: returns all comments across the entire workspace or share. With {node_id}: returns only comments on that specific file or folder.

Note: Only comments created after 2026-03-15 are included in scope-level results (without {node_id}); older comments are accessible via the node-level endpoint.

Auth: Required (JWT). Rate limited.

Query Parameters

ParameterTypeRequiredDefaultConstraintsDescription
sort string No asc "asc" or "desc" Sort order by creation time
limit integer No Min: 2, Max: 200 Number of comments to return
offset integer No 0 Min: 0 Number of comments to skip
page integer No Min: 1 Page number (alternative to offset-based pagination)
include_deleted boolean No false Include soft-deleted comments in results
reference_type string No Filter by reference anchor type: "video", "image", "document", "general", or "audio" (see Reference Anchoring)
include_total boolean No false Include total count and pagination metadata in response

Request Example

curl -X GET "https://api.fast.io/current/comments/workspace/1234567890123456789/?limit=50&include_total=true" \
  -H "Authorization: Bearer {jwt_token}"

Response

{
  "result": true,
  "comments": [
    {
      "id": "abc123opaqueid",
      "entity": "xyz789opaqueid",
      "user_id": "1234567890123456789",
      "parent_id": null,
      "body": "This looks great!",
      "profile_type": "workspace",
      "profile_id": "1234567890123456789",
      "reference": null,
      "mentions": [],
      "reactions": {"👍": 2, "❤️": 1},
      "user_reaction": "👍",
      "version": 1,
      "can_edit": true,
      "can_delete": true,
      "can_reply": true,
      "created": "2025-01-15 10:30:00 UTC",
      "updated": "2025-01-15 10:30:00 UTC"
    }
  ],
  "count": 1,
  "allowed": true,
  "remaining": 95,
  "total": 5,
  "limit": 50,
  "offset": 0
}

Response Fields

FieldTypeDescription
response.comments array Array of comment objects
response.count int Number of comments in this response
response.allowed bool Whether the current user can post new comments (based on plan limits)
response.remaining int Remaining comments allowed under plan limit (only present if plan has a limit)
response.total int Total number of comments (only if include_total=true)
response.limit int Limit used in query (only if include_total=true)
response.offset int Offset used in query (only if include_total=true)

Access Levels

RoleAccess
Workspace Owner/MemberFull access — sees all comments
Share OwnerFull access — sees all comments
Share GuestFiltered — sees own comments; visibility of owner and other guest comments depends on share permissions

Error Responses

Error CodeHTTP StatusMessageCause
1605 (Invalid Input)406Invalid API format...Missing entity type or parent ID
1605 (Invalid Input)406Entity type must be "workspace", "share", or "fileshare"Invalid entity type
1680 (Access Denied)401Invalid entity or insufficient permissionsUser lacks access
1609 (Not Found)404Invalid entity or insufficient permissionsEntity not found
1610 (Internal Error)500Failed to retrieve commentsInternal error

Workspace node reads include File Share comments. A file shared through a File Share is the same node that lives in the owning workspace, so a workspace node read (GET /current/comments/workspace/{workspace_id}/{node_id}/) also returns comments left by File Share recipients on that file. Those File Share comments appear read-only in the workspace view: can_reply, can_edit, and can_delete are false (replies and edits to a File Share comment go through the File Share's own surface). The total count reflects everything visible in the listing (the workspace's own comments plus the File Share comments), while the allowed / remaining fields reflect only the workspace's own writable comments — so remaining is not reduced by File Share comments you cannot edit. This inclusion is one-directional: workspace members see File Share comments, but File Share recipients never see the workspace's internal comments.


Create or Update Comment

POST /current/comments/{entity_type}/{parent_id}/

Create a new comment or update an existing one on an entity.

POST /current/comments/{entity_type}/{parent_id}/{node_id}/

Create a new comment or update an existing one on a specific node.

Auth: Required (JWT). Rate limited.

Content-Type: application/json

Request Body

FieldTypeRequiredConstraintsDescription
body string Required 1–8192 chars (raw); display text excluding mentions max 500 chars Comment text content
comment_id string No Valid opaque ID Include to update an existing comment; omit to create new
parent_id string No Valid opaque ID Parent comment ID for threaded reply (single-level only). Note: This is the parent comment's opaque ID, not the workspace/share ID from the URL path {parent_id}.
properties object No Arbitrary key-value metadata to attach
reference object No See Reference Anchoring Anchoring reference to a position in a file
target_id string No Valid object ID Inline attachment on a new comment — a single object to attach (see Comment Attachments). Ignored on update
target_ids array<string> No Non-empty array Inline attachments on a new comment — multiple objects to attach, up to 25 per comment. Ignored on update

Request Example — Create a new comment

curl -X POST "https://api.fast.io/current/comments/workspace/1234567890123456789/" \
  -H "Authorization: Bearer {jwt_token}" \
  -H "Content-Type: application/json" \
  -d '{
    "body": "Great work on this document!"
  }'

Request Example — Reply to a comment

curl -X POST "https://api.fast.io/current/comments/workspace/1234567890123456789/" \
  -H "Authorization: Bearer {jwt_token}" \
  -H "Content-Type: application/json" \
  -d '{
    "body": "Thanks for the feedback!",
    "parent_id": "abc123opaqueid"
  }'

Request Example — Comment with mention and page reference

curl -X POST "https://api.fast.io/current/comments/workspace/1234567890123456789/" \
  -H "Authorization: Bearer {jwt_token}" \
  -H "Content-Type: application/json" \
  -d '{
    "body": "Hey @[user:9876543210987654321:Jane Smith], can you review page 3?",
    "reference": {"type": "document", "page": 3}
  }'

Request Example — Update an existing comment

curl -X POST "https://api.fast.io/current/comments/workspace/1234567890123456789/" \
  -H "Authorization: Bearer {jwt_token}" \
  -H "Content-Type: application/json" \
  -d '{
    "comment_id": "def456opaqueid",
    "body": "Updated: This looks great after the revision."
  }'

Response

{
  "result": true,
  "comment": {
    "id": "abc123opaqueid",
    "entity": "xyz789opaqueid",
    "user_id": "1234567890123456789",
    "parent_id": null,
    "body": "Great work on this document!",
    "profile_type": "workspace",
    "profile_id": "1234567890123456789",
    "reference": null,
    "reactions": {},
    "user_reaction": null,
    "version": 1,
    "can_edit": true,
    "can_delete": true,
    "can_reply": true,
    "created": "2025-01-15 10:30:00 UTC",
    "updated": "2025-01-15 10:30:00 UTC"
  }
}

Response Fields

FieldTypeDescription
response.comment object The created or updated comment object (full schema above)

Access Levels

RoleAccess
Workspace Owner/MemberCan create and edit own comments
Share OwnerCan create and edit own comments
Share GuestCan only post if comments are enabled on the share

Error Responses

Error CodeHTTP StatusMessageCause
1680 (Access Denied)401Authentication required to post commentsUser not authenticated
1605 (Invalid Input)406Invalid JSON in request bodyMalformed JSON
1605 (Invalid Input)406Comment body must be between 1 and 8192 charactersBody length out of range
1605 (Invalid Input)406Comment text (excluding mentions) must not exceed 500 charactersDisplay text too long
1605 (Invalid Input)406Your comment appears to contain spam content...Spam detected
1605 (Invalid Input)406Invalid parent comment ID formatMalformed parent_id
1609 (Not Found)404Parent comment not foundReferenced parent does not exist
1605 (Invalid Input)406Parent comment belongs to different entityParent is on a different entity
1605 (Invalid Input)406Invalid reference data: ...Reference failed validation
1605 (Invalid Input)406Comment limit exceeded for your planPlan comment limit reached
1609 (Not Found)404Comment not foundComment ID for update not found
1680 (Access Denied)401You do not have permission to edit this commentUser is not the comment author
1609 (Not Found)404Linked entity not foundTask to link is missing, soft-deleted, cross-tenant, or inaccessible
1610 (Internal Error)500Failed to save commentInternal error

Notes


File Share Comments

GET /current/comments/fileshare/{fileshare_id}/{node_id}/

List a File Share recipient's comments on a node.

POST /current/comments/fileshare/{fileshare_id}/{node_id}/

Create or update a comment as a File Share recipient.

fileshare is a third {entity_type} on the comment surface, used by File Share recipients to read and post comments on a file inside a File Share. It shares the request/response shapes of the workspace/share List and Create endpoints above — the only differences are the fileshare discriminator and that the {node_id} segment is required (a File Share comment always targets a specific node, never the whole container).

Auth: Required. The caller must have access to the File Share (a signed-in recipient); anonymous callers are denied. Comments left here are the File Share recipient's own comments on the node.

Path Parameters

ParameterTypeFormatDescription
{fileshare_id} string 19-digit numeric File Share profile ID
{node_id} string Alphanumeric opaque ID The file or folder node within the File Share. Required

Request Example — list

curl -X GET "https://api.fast.io/current/comments/fileshare/1234567890123456789/n1o2p3q4r5s6t7u8v9w0x1/" \
  -H "Authorization: Bearer {jwt_token}"

Request Example — create

curl -X POST "https://api.fast.io/current/comments/fileshare/1234567890123456789/n1o2p3q4r5s6t7u8v9w0x1/" \
  -H "Authorization: Bearer {jwt_token}" \
  -H "Content-Type: application/json" \
  -d '{"body": "Received — thanks for sending this over."}'

The list and create responses use the same envelope and Comment Object schema as the entity-scoped endpoints above. A File Share comment carries the File Share's ID in scope_id, and — for an externally-authored comment — the external_author_* fields identify the author while user_id is null.

Notes

Error Responses

Error CodeHTTP StatusMessageCause
1605 (Invalid Input)406Entity type must be "workspace", "share", or "fileshare"Invalid entity type
1680 (Access Denied)401Invalid entity or insufficient permissionsCaller cannot access the File Share
1609 (Not Found)404Invalid entity or insufficient permissionsFile Share or node not found

Update Comment by ID

POST /current/comments/{comment_id}/update/

Edit an existing comment by its ID. Author-only. Works for every comment surface — workspace, share, node, and File Share.

Auth: Required (JWT). Rate limited.

Content-Type: application/json

Request Body

FieldTypeRequiredConstraintsDescription
body string Required 1–8192 chars (raw); display text excluding mentions max 500 chars Replacement comment text
properties object No Arbitrary key-value metadata to merge
reference object No See Reference Anchoring Replacement anchoring reference

Request Example

curl -X POST "https://api.fast.io/current/comments/abc123opaqueid/update/" \
  -H "Authorization: Bearer {jwt_token}" \
  -H "Content-Type: application/json" \
  -d '{
    "body": "Updated: this looks great after the revision."
  }'

Response

The full updated comment object (same shape as Create or Update Comment above), with edited_at populated.

Error Responses

Error CodeHTTP StatusMessageCause
1605 (Invalid Input)406Comment body must be between 1 and 8192 charactersBody length out of range
1605 (Invalid Input)406Comment is deletedThe comment has been deleted
1609 (Not Found)404Comment not foundUnknown comment ID, or the comment's surface is not visible to you
1680 (Access Denied)401You do not have permission to edit this commentCaller is not the comment author

Notes


Get Comment Details

GET /current/comments/{comment_id}/details/

Get a single comment's full details.

Auth: Required (JWT). Rate limited.

Request Example

curl -X GET "https://api.fast.io/current/comments/abc123opaqueid/details/" \
  -H "Authorization: Bearer {jwt_token}"

Response

{
  "result": true,
  "comment": {
    "id": "abc123opaqueid",
    "entity": "xyz789opaqueid",
    "user_id": "1234567890123456789",
    "parent_id": null,
    "body": "This looks great!",
    "profile_type": "workspace",
    "profile_id": "1234567890123456789",
    "reference": null,
    "reactions": {},
    "user_reaction": null,
    "version": 1,
    "can_edit": true,
    "can_delete": true,
    "can_reply": true,
    "created": "2025-01-15 10:30:00 UTC",
    "updated": "2025-01-15 10:30:00 UTC",
    "deleted": null
  }
}

Error Responses

Error CodeHTTP StatusMessageCause
1605 (Invalid Input)406Comment ID is requiredMissing comment ID
1605 (Invalid Input)406Invalid comment ID formatMalformed opaque ID
1609 (Not Found)404Comment not foundComment does not exist
1680 (Access Denied)401You do not have permission to view this commentUser lacks access to the entity

Delete Comment

DELETE /current/comments/{comment_id}/delete/

Soft-delete a comment. Recursive — also deletes all replies to this comment.

Who can delete: the comment's author, and workspace/share admins or owners (moderation — admins can remove any comment on their workspace or share). File Share comments can only be deleted by their author; they are never moderator-deletable, including from the workspace view. The can_delete flag on every returned comment reflects this, so clients should drive the delete affordance from can_delete.

Auth: Required (JWT). Rate limited.

Request Example

curl -X DELETE "https://api.fast.io/current/comments/abc123opaqueid/delete/" \
  -H "Authorization: Bearer {jwt_token}"

Response

{
  "result": true,
  "message": "Comment deleted successfully",
  "comment": {
    "id": "abc123opaqueid",
    "entity": "xyz789opaqueid",
    "user_id": "1234567890123456789",
    "parent_id": null,
    "body": "This looks great!",
    "profile_type": "workspace",
    "profile_id": "1234567890123456789",
    "reference": null,
    "reactions": {},
    "user_reaction": null,
    "version": 1,
    "can_edit": false,
    "can_delete": false,
    "can_reply": false,
    "created": "2025-01-15 10:30:00 UTC",
    "updated": "2025-01-16 08:00:00 UTC",
    "deleted": "2025-01-16 08:00:00 UTC"
  }
}

Access Levels

RoleAccess
Comment AuthorCan delete own comments
Entity OwnerCan delete any comment on their entity
Other UsersDenied

Error Responses

Error CodeHTTP StatusMessageCause
1605 (Invalid Input)406Comment ID is requiredMissing comment ID
1605 (Invalid Input)406Invalid comment ID formatMalformed opaque ID
1609 (Not Found)404Comment not foundComment does not exist
1605 (Invalid Input)406Comment is already deletedComment was previously deleted
1680 (Access Denied)401You do not have permission to delete this commentNot author or entity owner
1610 (Internal Error)500Failed to delete commentInternal error

Bulk Delete Comments

POST /current/comments/bulk/delete/

Bulk soft-delete multiple comments. Each comment is processed independently — partial success is possible. NOT recursive — does not delete replies.

Auth: Required (JWT). Rate limited.

Content-Type: application/json

Request Body

FieldTypeRequiredConstraintsDescription
comment_ids array<string> Required Max 100 items Array of comment opaque IDs to delete

Request Example

curl -X POST "https://api.fast.io/current/comments/bulk/delete/" \
  -H "Authorization: Bearer {jwt_token}" \
  -H "Content-Type: application/json" \
  -d '{"comment_ids": ["abc123opaqueid", "def456opaqueid", "ghi789opaqueid"]}'

Response

{
  "result": true,
  "success": true,
  "deleted_count": 3,
  "failed_count": 0,
  "total_count": 3,
  "results": {
    "abc123opaqueid": {"id": "abc123opaqueid", "success": true, "error": null},
    "def456opaqueid": {"id": "def456opaqueid", "success": true, "error": null},
    "ghi789opaqueid": {"id": "ghi789opaqueid", "success": true, "error": null}
  }
}

Response Fields

FieldTypeDescription
response.success bool true only if all comments were deleted (failed_count === 0)
response.deleted_count int Number of successfully deleted comments
response.failed_count int Number that failed to delete
response.total_count int Total number of IDs provided
response.results object Per-comment results keyed by comment ID
response.results.{id}.success bool Whether this comment was deleted
response.results.{id}.error string|null Error message if failed, null on success

Per-Comment Error Messages

ErrorCause
Invalid comment ID formatNot a valid opaque ID
Comment not foundNo comment with this ID
Comment already deletedPreviously soft-deleted
Permission deniedUser is not author or entity owner
Failed to delete commentInternal error
Processing errorUnhandled error while processing this comment

Request-Level Error Responses

Error CodeHTTP StatusMessageCause
1605 (Invalid Input)406Invalid JSON request bodyMalformed JSON
1605 (Invalid Input)406comment_ids array is requiredMissing or non-array field
1605 (Invalid Input)406comment_ids array cannot be emptyEmpty array
1605 (Invalid Input)406Maximum 100 comments can be deleted at onceExceeds bulk limit

Important: Unlike single delete, bulk delete does not recursively delete replies.


Add or Change Reaction

POST /current/comments/{comment_id}/reactions/

Add an emoji reaction to a comment. One reaction per user per comment — sending a new reaction replaces any previous one.

Auth: Required (JWT). Rate limited.

Content-Type: application/json

Request Body

FieldTypeRequiredConstraintsDescription
emoji string Required Single emoji character; max 2 UTF-8 characters; must match Unicode emoji ranges Emoji to react with

Request Example

curl -X POST "https://api.fast.io/current/comments/abc123opaqueid/reactions/" \
  -H "Authorization: Bearer {jwt_token}" \
  -H "Content-Type: application/json" \
  -d '{"emoji": "👍"}'

Response

{
  "result": true,
  "reactions": {"👍": 3, "❤️": 1},
  "user_reaction": "👍"
}

Response Fields

FieldTypeDescription
response.reactions object Map of emoji to total reaction count across all users
response.user_reaction string|null The current user's active reaction emoji

Error Responses

Error CodeHTTP StatusMessageCause
1605 (Invalid Input)406Comment ID is requiredMissing comment ID
1605 (Invalid Input)406Invalid comment ID formatMalformed opaque ID
1609 (Not Found)404Comment not foundComment does not exist or is deleted
1680 (Access Denied)401You do not have permission to react to this commentUser lacks entity access
1605 (Invalid Input)406emoji parameter is requiredMissing or non-string emoji
1605 (Invalid Input)406Invalid emoji characterDoes not match Unicode emoji pattern
1605 (Invalid Input)406Only single emoji allowedString exceeds 2 UTF-8 characters
1610 (Internal Error)500Failed to save reactionInternal error

Remove Reaction

DELETE /current/comments/{comment_id}/reactions/

Remove an emoji reaction from a comment.

Auth: Required (JWT). Rate limited.

Content-Type: application/json

Request Body

FieldTypeRequiredConstraintsDescription
emoji string No Must match Unicode emoji ranges if provided Specific emoji to remove. Omit to remove any reaction by the current user

Request Example — Remove specific emoji

curl -X DELETE "https://api.fast.io/current/comments/abc123opaqueid/reactions/" \
  -H "Authorization: Bearer {jwt_token}" \
  -H "Content-Type: application/json" \
  -d '{"emoji": "👍"}'

Request Example — Remove any reaction

curl -X DELETE "https://api.fast.io/current/comments/abc123opaqueid/reactions/" \
  -H "Authorization: Bearer {jwt_token}" \
  -H "Content-Type: application/json" \
  -d '{}'

Response

{
  "result": true,
  "reactions": {"❤️": 1},
  "user_reaction": null
}

Response Fields

FieldTypeDescription
response.reactions object Updated map of emoji to total reaction count
response.user_reaction string|null Current user's reaction after removal (null if removed)

Error Responses

Error CodeHTTP StatusMessageCause
1605 (Invalid Input)406Comment ID is requiredMissing comment ID
1605 (Invalid Input)406Invalid comment ID formatMalformed opaque ID
1609 (Not Found)404Comment not foundComment does not exist or is deleted
1680 (Access Denied)401You do not have permission to react to this commentUser lacks entity access
1605 (Invalid Input)406emoji must be a stringNon-string emoji parameter
1605 (Invalid Input)406Invalid emoji characterDoes not match Unicode emoji pattern
1610 (Internal Error)500Failed to remove reactionInternal error

Notes: Removing a reaction that does not exist returns success (idempotent). A "removed" event is triggered only when a reaction was actually removed.


Comment Attachments

Attach arbitrary platform objects to a comment to give it context — a file or folder, a sign envelope, a share, a File Share, or a workspace. An attachment is a lightweight reference: it records what is attached, not a copy of it.

Attachment Object (hydrated)

Every attachment returned by the API is hydrated and access-gated to the caller: an object the caller cannot see (or that no longer exists) is returned with available: false and display_name: null rather than leaking its name. Render defensively: when available is false, never show a name.

FieldTypeDescription
target_idstringThe attached object's ID (19-digit numeric for a workspace/share/envelope/File Share, or an opaque ID for a file/folder node)
target_typestringCoarse object type: node, envelope, share, workspace, or fileshare
kindstringAlias of target_type (same value)
display_namestring|nullThe object's resolved display name, or null when the caller cannot see it or it has no name
availablebooltrue when the caller can access the object (and display_name is authoritative); false when it is inaccessible, missing, or could not be resolved

List Comment Attachments

GET /current/comments/{comment_id}/attachments/

List all objects attached to a comment, hydrated and access-gated to the caller.

Auth: Required (JWT). Rate limited.

Response

{
  "result": true,
  "comment_id": "abc123opaqueid",
  "attachments": [
    {
      "target_id": "n1o2p3q4r5s6t7u8v9w0x1y2z3a4b5",
      "target_type": "node",
      "kind": "node",
      "display_name": "spec.pdf",
      "available": true
    },
    {
      "target_id": "9876543210987654321",
      "target_type": "share",
      "kind": "share",
      "display_name": null,
      "available": false
    }
  ],
  "count": 2
}

Attach Objects to a Comment

POST /current/comments/{comment_id}/attachments/

Attach one object (target_id) or many (target_ids) to a comment. Idempotent; the new objects are committed atomically. Returns the full, updated hydrated attachment list.

Auth: Required (JWT). Rate limited. Content-Type: application/json.

Request Body

FieldTypeRequiredConstraintsDescription
target_idstringOne of target_id / target_idsValid object IDA single object to attach
target_idsarray<string>One of target_id / target_idsNon-empty arrayMultiple objects to attach

A request whose new attachments would push the comment over the 25-attachment cap is rejected before anything is written.

Request Example — single

curl -X POST "https://api.fast.io/current/comments/abc123opaqueid/attachments/" \
  -H "Authorization: Bearer {jwt_token}" \
  -H "Content-Type: application/json" \
  -d '{"target_id": "n1o2p3q4r5s6t7u8v9w0x1y2z3a4b5"}'

Request Example — bulk

curl -X POST "https://api.fast.io/current/comments/abc123opaqueid/attachments/" \
  -H "Authorization: Bearer {jwt_token}" \
  -H "Content-Type: application/json" \
  -d '{"target_ids": ["n1o2p3q4r5s6t7u8v9w0x1y2z3a4b5", "9876543210987654321"]}'

Response

{
  "result": true,
  "comment_id": "abc123opaqueid",
  "attached": 1,
  "attachments": [
    {
      "target_id": "n1o2p3q4r5s6t7u8v9w0x1y2z3a4b5",
      "target_type": "node",
      "kind": "node",
      "display_name": "spec.pdf",
      "available": true
    }
  ],
  "count": 1
}

Response Fields

FieldTypeDescription
comment_idstringThe comment the attachments belong to
attachedintNumber of objects newly attached by this request (0 when every target was already attached)
attachmentsarrayThe full hydrated attachment list after the operation
countintNumber of attachments in the list

Error Responses

Error CodeHTTP StatusMessageCause
1605 (Invalid Input)406A target_id or non-empty target_ids array is requiredNo target supplied
1605 (Invalid Input)406Invalid attachment targetA target ID could not be decoded
1605 (Invalid Input)406Attachment limit reached (maximum 25 per comment)The new attachments would exceed the cap
1680 (Access Denied)401You do not have permission to modify attachments on this commentCaller is not the comment author
1609 (Not Found)404Comment not foundComment does not exist, is not visible to you, or is trashed

Detach an Object from a Comment

POST /current/comments/{comment_id}/attachments/detach/

Remove an attachment by its target_id. Idempotent — detaching an object that is not attached returns success with removed: false. Returns the updated hydrated attachment list.

Auth: Required (JWT). Rate limited. Content-Type: application/json.

Request Body

FieldTypeRequiredConstraintsDescription
target_idstringYesValid object IDThe object to detach

Response

{
  "result": true,
  "comment_id": "abc123opaqueid",
  "removed": true,
  "attachments": [],
  "count": 0
}

Response Fields

FieldTypeDescription
comment_idstringThe comment the attachment belonged to
removedbooltrue if an attachment was actually removed; false if the object was not attached
attachmentsarrayThe full hydrated attachment list after the operation
countintNumber of attachments remaining

Attaching at comment-create time (inline)

You can attach objects when creating a comment by including target_id or target_ids in the comment-create body (see Create or Update Comment). Inline attachments apply only to a new comment — they are ignored on an update, and the comment plus its attachments are written together so the comment never appears without them. An invalid target or one that would exceed the cap rejects the whole create.

attachment_count is returned on every comment list row and on the comment detail response. The hydrated attachments array is returned only on the comment detail response (GET /current/comments/{comment_id}/details/). All counts are computed live on each read.


Threading

Comments support single-level threading only.

Comment A (top-level)
├── Comment B (reply to A)
├── Comment C (reply to B → auto-flattened to reply to A)
└── Comment D (reply to A)

Mentions

Use mention markup in the body field to tag other users:

@[user:USER_ID:Display Name]
ComponentDescription
userLiteral prefix (always user)
USER_IDThe user's 19-digit numeric profile ID
Display NameDisplay name to show in the UI

Character limit details

Example body with mentions

Hey @[user:1234567890123456789:Jane Smith] and @[user:9876543210987654321:Bob Jones], please review this file.

Reference Anchoring

Comments can be anchored to a specific position within a file using the reference object. The type field is required and selects which additional fields are valid.

type values

typeApplies toValid anchor fields
"video"Video filestimestamp (or timestamp_start + timestamp_end); optional region
"audio"Audio filestimestamp (or timestamp_start + timestamp_end)
"document"Documents / textpage, text_snippet
"image"Imagesregion
"general"Any filenone (a bare {"type": "general"} anchor)

Anchor fields

FieldTypeUsed withDescription
timestamp number video, audio Position in seconds (non-negative). Mutually exclusive with the range fields
timestamp_start / timestamp_end number video, audio A time range in seconds (both non-negative, end > start)
page integer document Page number (positive integer)
text_snippet string document The referenced text passage (max 500 characters)
region object video, image Rectangular area with keys x1, y1, x2, y2, each a number 0–100 (percent of width/height), with x2 > x1 and y2 > y1

Any unrecognized type is rejected with "Invalid reference type: {value}".

Example — Video timestamp

{
  "body": "The transition at this point needs work.",
  "reference": {"type": "video", "timestamp": 42.5}
}

Example — Document page

{
  "body": "Typo in the second paragraph.",
  "reference": {"type": "document", "page": 7}
}

Example — Image region

{
  "body": "This area needs higher contrast.",
  "reference": {"type": "image", "region": {"x1": 20, "y1": 15, "x2": 55, "y2": 40}}
}

Example — Document text snippet

{
  "body": "This sentence should be rephrased.",
  "reference": {"type": "document", "text_snippet": "The quick brown fox jumps over the lazy dog."}
}

Content Filtering

Comment bodies undergo automatic filtering:

↑ Back to top