> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sublay.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Comments

> Create and manage threaded comments and reactions

export const SpaceReputationParams = ({variant = "context", field = "path"}) => {
  const isUser = variant === "user";
  return <>
      <ParamField {...{
    [field]: "spaceReputation",
    type: "object"
  }}>
        Opt-in. Adds a <code>spaceReputation</code> number to each returned user,
        scoped to a single space. Requires the <code>reputation</code> bundle.
        The <code>reputation</code> total is always present regardless;{" "}
        <code>spaceReputation</code> is purely additive and only appears when you
        pass this object. <strong>This object is the primary form</strong> — it
        replaces the deprecated flat props below. See the{" "}
        <a href="/v8/data-models/reputation">Reputation data model</a> for the
        full contract.

        <Expandable title="spaceReputation">
          {isUser ? <ParamField name="spaceId" type="string | &quot;none&quot;" required>
              Which bucket to read. A space <strong><code>&lt;uuid&gt;</code></strong> reads that
              space's bucket; <strong><code>"none"</code></strong> reads the
              project-general (space-less) bucket.{" "}
              <strong><code>"context"</code> is rejected (400)</strong> on this
              endpoint — there is no space context to derive. The empty string
              and the legacy <code>general</code> / <code>null</code> aliases are
              also rejected. Missing buckets read as <code>0</code>.
            </ParamField> : <ParamField name="spaceId" type="string | &quot;none&quot; | &quot;context&quot;" required>
              Which bucket to read. One of: a space <strong><code>&lt;uuid&gt;</code></strong>{" "}
              (that space's bucket), <strong><code>"none"</code></strong> (the
              project-general, space-less bucket), or{" "}
              <strong><code>"context"</code></strong> (the space derived from the
              request context — resolved per-row on lists, or the single space on
              member/team/conversation surfaces). The empty string and the legacy{" "}
              <code>general</code> / <code>null</code> aliases are rejected (400).
              Missing buckets read as <code>0</code>.
            </ParamField>}
          <ParamField name="includeDescendants" type="boolean">
            Only honored when <code>spaceId</code> is an explicit space <code>&lt;uuid&gt;</code>.
            When <code>true</code>, <code>spaceReputation</code> is the{" "}
            <strong>subtree sum</strong> — the named space plus all of its
            descendant spaces (the root space's own bucket included). Ignored for{" "}
            <code>"none"</code>; not allowed with <code>"context"</code>.
          </ParamField>
        </Expandable>
      </ParamField>

      {isUser ? <ParamField {...{
    [field]: "spaceReputationId",
    type: "string",
    deprecated: true
  }}>
          <strong>Deprecated</strong> — use the <code>spaceReputation</code>{" "}
          object instead. The flat form of <code>spaceReputation.spaceId</code>.
          Still accepted (the object wins if both are passed); removal is a later
          major version. Accepts a space <code>&lt;uuid&gt;</code> or <code>"none"</code> only —{" "}
          <code>"context"</code> is rejected (400) on this endpoint.
        </ParamField> : <ParamField {...{
    [field]: "spaceReputationId",
    type: "string",
    deprecated: true
  }}>
          <strong>Deprecated</strong> — use the <code>spaceReputation</code>{" "}
          object instead. The flat form of <code>spaceReputation.spaceId</code>.
          Still accepted (the object wins if both are passed); removal is a later
          major version. Accepts a space <code>&lt;uuid&gt;</code>, <code>"none"</code>, or{" "}
          <code>"context"</code>.
        </ParamField>}

      <ParamField {...{
    [field]: "spaceReputationDescendants",
    type: "boolean",
    deprecated: true
  }}>
        <strong>Deprecated</strong> — use{" "}
        <code>spaceReputation.includeDescendants</code> instead. The flat form,
        only honored alongside an explicit <code>spaceReputationId</code> <code>&lt;uuid&gt;</code>.
      </ParamField>
    </>;
};

Comments are threaded discussions attached to entities. The `comments` module lets you create, fetch, update, and delete comments, and manage reactions on them. All actions are performed on behalf of the logged-in user.

***

### createComment

Creates a comment on an entity. Optionally a reply, with a GIF, mentions, attachments, or metadata.

```typescript theme={null}
const comment = await sublay.comments.createComment({
  entityId: "ent_xyz789",
  content: "Great post!",
});
```

<ParamField body="entityId" type="string" required>
  The Sublay entity ID the comment belongs to.
</ParamField>

<ParamField body="foreignId" type="string">
  Your application's identifier for this comment.
</ParamField>

<ParamField body="content" type="string">
  The comment's text content.
</ParamField>

<ParamField body="gif" type="GifData | null">
  An optional GIF attached to the comment.
</ParamField>

<ParamField body="mentions" type="Mention[]">
  User mentions embedded in the comment.
</ParamField>

<ParamField body="parentId" type="string | null">
  The ID of the parent comment when this is a reply.
</ParamField>

<ParamField body="referencedCommentId" type="string">
  The ID of another comment this comment references.
</ParamField>

<ParamField body="attachments" type="Record<string, any>[]">
  File or media attachments.
</ParamField>

<ParamField body="metadata" type="Record<string, any>">
  Arbitrary public metadata.
</ParamField>

**Returns** — `Promise<Comment>`

When the server refuses the comment, the call rejects with its error — among them `403 comment/parent-deleted` and `403 comment/parent-removed` for a reply to a deleted or removed comment, `403 comment/referenced-deleted` and `403 comment/referenced-removed` for a quote of one, and `409 comment/foreign-id-taken` for a `foreignId` already in use. See [Create Comment → Error Responses](/v8/api-reference/comments/create-comment#error-responses) for the full list.

***

### fetchComment

Fetches a single comment by its ID.

```typescript theme={null}
const comment = await sublay.comments.fetchComment({ commentId: "cmt_abc123" });
```

<ParamField body="commentId" type="string" required>
  The Sublay comment ID.
</ParamField>

<ParamField body="include" type="string">
  Comma-separated list of associations to populate.
</ParamField>

<SpaceReputationParams variant="context" field="body" />

**Returns** — `Promise<Comment>`

***

### fetchCommentByForeignId

Fetches a comment by your application's own identifier.

```typescript theme={null}
const comment = await sublay.comments.fetchCommentByForeignId({
  foreignId: "comment-99",
});
```

<ParamField body="foreignId" type="string" required>
  Your application's comment identifier.
</ParamField>

<ParamField body="include" type="string">
  Comma-separated list of associations to populate.
</ParamField>

**Returns** — `Promise<Comment>`

***

### updateComment

Updates a comment's content.

```typescript theme={null}
const comment = await sublay.comments.updateComment({
  commentId: "cmt_abc123",
  content: "Edited comment text",
});
```

<ParamField body="commentId" type="string" required>
  The Sublay comment ID to update.
</ParamField>

<ParamField body="content" type="string" required>
  The new content for the comment.
</ParamField>

**Returns** — `Promise<Comment>`

***

### deleteComment

Deletes a comment.

```typescript theme={null}
await sublay.comments.deleteComment({ commentId: "cmt_abc123" });
```

<ParamField body="commentId" type="string" required>
  The Sublay comment ID to delete.
</ParamField>

**Returns** — `Promise<void>`

***

### fetchManyComments

Fetches one level of a comment thread, cursor-paginated: an entity's top-level comments (`entityId`) or a comment's direct replies (`parentId`). One of the two is required. Optionally nests a few levels of replies inside each returned comment. See [Fetch Many Comments](/v8/api-reference/comments/fetch-many-comments) for the full contract — placeholders, block flags and the request size limit.

```typescript theme={null}
const { data, pagination } = await sublay.comments.fetchManyComments({
  entityId: "ent_xyz789",
  sortBy: "top",
  limit: 20,
  include: "user",
  replyDepth: 2, // also bring 2 levels of replies…
  replyLimit: 3, // …up to 3 per comment
});

// Next page
const next = await sublay.comments.fetchManyComments({
  entityId: "ent_xyz789",
  sortBy: "top",
  limit: 20,
  cursor: pagination.nextCursor,
});
```

For a user's comments across entities, use [`users.fetchCommentsByUserId`](/v8/js-sdk/users#fetchcommentsbyuserid).

<ParamField body="entityId" type="string">
  Fetch this entity's top-level comments. Required unless `parentId` is passed.
</ParamField>

<ParamField body="parentId" type="string">
  Fetch this comment's direct replies. Required unless `entityId` is passed.
</ParamField>

<ParamField body="limit" type="number">
  How many comments at the level being fetched. Server default `10`, max `100`.
</ParamField>

<ParamField body="cursor" type="string | null">
  `pagination.nextCursor` from the previous response, passed as returned. Omit it, or pass `null`, for the first page. Send the same `sortBy`, `sortDir` and `sortByReaction` as the request that returned it.
</ParamField>

<ParamField body="sortBy" type="&#x22;createdAt&#x22; | &#x22;top&#x22; | &#x22;controversial&#x22;">
  Sort for the level being fetched. `"top"` ranks by the raw count of `sortByReaction`. Server default `"createdAt"`. `"new"` / `"old"` are deprecated aliases for `"createdAt"` — the server still accepts them but responds with a deprecation header.
</ParamField>

<ParamField body="sortDir" type="&#x22;asc&#x22; | &#x22;desc&#x22;">
  Applies to every sort. Server default `"desc"`.
</ParamField>

<ParamField body="sortByReaction" type="ReactionType">
  With `sortBy: "top"` only: the reaction to rank by. Server default `"upvote"`.
</ParamField>

<ParamField body="replyDepth" type="number">
  Levels of replies to nest under each returned comment (`0`–`5`). Server default `0`.
</ParamField>

<ParamField body="replyLimit" type="number">
  Replies per comment in the nested levels (at least `1`). Server default `3`.
</ParamField>

<ParamField body="replySortBy" type="&#x22;createdAt&#x22; | &#x22;top&#x22; | &#x22;controversial&#x22;">
  Sort for the nested levels. Defaults to `sortBy`.
</ParamField>

<ParamField body="replySortDir" type="&#x22;asc&#x22; | &#x22;desc&#x22;">
  Sort direction for the nested levels. Defaults to `sortDir`.
</ParamField>

<ParamField body="replySortByReaction" type="ReactionType">
  The reaction the nested levels rank by, when their sort is `"top"`.
</ParamField>

<ParamField body="include" type="&#x22;user&#x22; | &#x22;grants&#x22; | (&#x22;user&#x22; | &#x22;grants&#x22;)[]">
  Related data to populate, at every level.
</ParamField>

<SpaceReputationParams variant="context" field="body" />

**Returns** — `Promise<CursorPaginatedResponse<Comment>>` — `{ data, pagination: { nextCursor, hasMore } }`. With `replyDepth` above `0`, each comment carries nested `replies` in the same shape.

***

### addReaction

Adds the logged-in user's reaction to a comment and returns the full populated comment.

```typescript theme={null}
const comment = await sublay.comments.addReaction({
  commentId: "cmt_abc123",
  reactionType: "like",
});
```

<ParamField body="commentId" type="string" required>
  The Sublay comment ID.
</ParamField>

<ParamField body="reactionType" type="ReactionType" required>
  One of: `"upvote"`, `"downvote"`, `"like"`, `"love"`, `"wow"`, `"sad"`, `"angry"`, `"funny"`.
</ParamField>

**Returns** — `Promise<Comment>`

***

### removeReaction

Removes the logged-in user's reaction from a comment and returns the full populated comment.

```typescript theme={null}
const comment = await sublay.comments.removeReaction({
  commentId: "cmt_abc123",
});
```

<ParamField body="commentId" type="string" required>
  The Sublay comment ID.
</ParamField>

**Returns** — `Promise<Comment>`

***

### fetchReactions

Fetches a paginated list of reactions on a comment, optionally filtered by reaction type.

```typescript theme={null}
const { data, pagination } = await sublay.comments.fetchReactions({
  commentId: "cmt_abc123",
  reactionType: "like",
  page: 1,
  limit: 20,
});
```

<ParamField body="commentId" type="string" required>
  The Sublay comment ID.
</ParamField>

<ParamField body="reactionType" type="ReactionType">
  Filter to a specific reaction type.
</ParamField>

<ParamField body="page" type="number">
  Page number (1-indexed).
</ParamField>

<ParamField body="limit" type="number">
  Results per page.
</ParamField>

<ParamField body="sortDir" type="string">
  Sort direction: `"asc"` or `"desc"`.
</ParamField>

<SpaceReputationParams variant="context" field="body" />

**Returns** — `Promise<{ data: Reaction[]; pagination: { page: number; limit: number; total: number; totalPages: number; hasMore: boolean } }>`

***

### getUserReaction

Gets the logged-in user's reaction on a comment. Returns `null` if there is no reaction.

```typescript theme={null}
const { reactionType } = await sublay.comments.getUserReaction({
  commentId: "cmt_abc123",
});
// reactionType is "like" | "upvote" | ... | null
```

<ParamField body="commentId" type="string" required>
  The Sublay comment ID.
</ParamField>

**Returns** — `Promise<{ reactionType: ReactionType | null }>`. Rejects with `404 comment/not-found` when the comment doesn't exist, or is on an entity whose author has blocked the user (the user's own comments excepted).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.