> ## 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.

# Fetch Comments by User

> Get a user's comment history — their comments at any depth, cursor-paginated

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>
    </>;
};

<Note>
  **Requires the `comments` bundle.** A project without the comments bundle returns `403 database/tables-not-available`. See [Bundles](/v8/bundles).
</Note>

Returns a user's comments as one flat list — top-level comments and replies alike, across every entity — cursor-paginated. Use it for profile pages and activity views. To render a discussion, use [Fetch Many Comments](/v8/api-reference/comments/fetch-many-comments) instead.

Authentication is optional. The history is read as the **caller**: the signed-in user, or — with a service or master key — the user named in `actingUserId`. Without one (no user token, or a key without `actingUserId`) the request is anonymous: deleted and moderator-removed comments are left out, no block rule applies, `isAuthorBlocked` and `isUnavailable` are always `false`, and `userReaction` isn't populated.

An unknown `userId` returns an empty page.

**What's in the list:**

* **Deleted comments** are left out.
* **Moderator-removed comments** are left out of other people's history. In the caller's **own** history they are included in full, marked `moderationStatus: "removed"`.
* **Blocks:** comments by a user the caller is [block-edged](/v8/sdk/moderation/overview#blocking) with are left out by default (see `blockedFilter`). Comments on an entity whose author has blocked the caller are left out too — except the caller's own (see [Your own comments on an unavailable entity](#your-own-comments-on-an-unavailable-entity)).

## Path Parameters

<ParamField path="userId" type="string" required>
  The Sublay user ID (UUID) of the user whose comments to list.
</ParamField>

## Query Parameters

### Acting user

<ParamField query="actingUserId" type="string">
  The user to read the history as. Takes effect only with a **service or master key**. A user token always reads as itself: naming its own ID changes nothing, and naming a different user returns `403 comment/unauthorized`. On a request with neither a key nor a user token it is ignored, and the request stays anonymous. With a key, the rules below (own removed comments, blocks, `blockedFilter`, the `isAuthorBlocked` / `isUnavailable` flags and `userReaction`) apply from that user's perspective.
</ParamField>

### Filtering

<ParamField query="entityId" type="string">
  Only comments on this entity.
</ParamField>

<ParamField query="sourceId" type="string">
  Only comments on entities with this `sourceId`. Applied whether or not `include` contains `entity`. On a project without the `entities` bundle, a request with `sourceId` returns an empty page.
</ParamField>

<ParamField query="blockedFilter" type="string" default="exclude">
  How comments by users the caller is block-edged with are treated. `"exclude"` (default) leaves them out. `"include-outbound-blocked"` re-includes comments by users the caller **themselves** blocked — returned in full and marked `isAuthorBlocked: true` — and never surfaces content from users who blocked the caller. Has no effect when the `moderation` bundle is not installed.
</ParamField>

### Pagination

<ParamField query="limit" type="number" default="10">
  Comments per batch. A whole number of at least `1` — `0`, a negative number or a non-integer value returns `400 comment/invalid-query`. Values above `100` are treated as `100`.
</ParamField>

<ParamField query="cursor" type="string">
  Leave it out on the first request (an empty `cursor` is treated the same way), then pass `pagination.nextCursor` from the previous response. Must be sent with the same `sortBy`, `sortDir` and `sortByReaction` it was created under. Cursors work as on the thread endpoint — see [Cursors](/v8/api-reference/comments/fetch-many-comments#cursors).
</ParamField>

### Sorting

<ParamField query="sortBy" type="string" default="createdAt">
  `createdAt`, `top` (raw count of `sortByReaction`) or `controversial` — the same meanings as on [Fetch Many Comments](/v8/api-reference/comments/fetch-many-comments#sorting). `new` and `old` are deprecated aliases for `createdAt` and receive a `Deprecation` response header.
</ParamField>

<ParamField query="sortDir" type="string" default="desc">
  `asc` or `desc`. Applies to every sort.
</ParamField>

<ParamField query="sortByReaction" type="string" default="upvote">
  With `sortBy=top` only: the reaction to rank by (`upvote`, `downvote`, `like`, `love`, `wow`, `sad`, `angry`, `funny`). Sending it with any other `sortBy` returns `400`.
</ParamField>

### Optional associations

<ParamField query="include" type="string">
  Comma-separated list of associations to include in each comment:

  * `user` — the comment author, with the avatar file URLs
  * `entity` — the entity the comment is on, as its stored record: the fields an entity fetch computes or joins (such as `commentsCount`, `userReaction` and `nsfwEffective`) are not included — see [The included entity](/v8/data-models/comment#the-included-entity); `null` when the entity isn't available to the caller (for example, removed by a moderator) — the comment is still returned
  * `space` — the entity's space, as `entity.space` (also includes `entity`); when `entity` is `null` there is no space
  * `parent` — `parentComment`, for replies; `null` when the parent no longer exists or is on another entity
  * `grants` — the [reputation-grant summary](/v8/data-models/reputation-grant#grantsummary)

  `include` never changes which comments are returned.
</ParamField>

### Space-scoped reputation

This endpoint accepts the opt-in reputation params, resolved against each comment's space. They add a `spaceReputation` field to each populated author `user`, alongside the always-present `reputation` total. Requires the `reputation` bundle. See the [Reputation data model](/v8/data-models/reputation).

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

## Response

```json theme={null}
{
  "data": [ ...Comment[] ],
  "pagination": { "nextCursor": "eyJ2Ijox…", "hasMore": true }
}
```

<ResponseField name="data" type="Comment[]">
  The user's comments, in sort order. Each item is a [Comment](/v8/data-models/comment), with `isAuthorBlocked` and `isUnavailable` flags. No comment carries nested `replies`.
</ResponseField>

<ResponseField name="pagination.nextCursor" type="string | null">
  Pass this as `cursor` to get the next batch. `null` when there's nothing more.
</ResponseField>

<ResponseField name="pagination.hasMore" type="boolean">
  Whether more comments exist after this batch. Exact.
</ResponseField>

An embedded `parentComment` follows the same rules as everywhere else: a deleted or removed parent is a [placeholder](/v8/data-models/comment#placeholders), and a parent whose author blocked the caller is a placeholder with `isUnavailable: true`.

### Your own comments on an unavailable entity

When the caller lists their **own** history, their comments on an entity whose author has blocked them stay in the list, so they can still find and delete them. On those comments, everything belonging to the entity's author is blanked: `entity` (which carries `space`) and `parentComment` are `null` when requested.

These comments are **read-and-delete only**: replying under them, reacting to them, and editing them are refused (`404`). They aren't marked by a dedicated field. `entity: null` only means the entity isn't available to the caller — it doesn't say why, so it doesn't identify these comments.

## Error Responses

<AccordionGroup>
  <Accordion title="Unsupported parameter — 400">
    `page` isn't supported — comments use cursor pagination.

    ```json theme={null}
    {
      "error": "`page` isn't supported on this endpoint. Comments use cursor pagination: leave `cursor` out on the first request, then pass `pagination.nextCursor` from the previous response to get the next batch.",
      "code": "comment/unsupported-param",
      "param": "page"
    }
    ```
  </Accordion>

  <Accordion title="Invalid user ID — 400">
    Returned with code `comment/invalid-params` when `userId` isn't a valid UUID.
  </Accordion>

  <Accordion title="Invalid query — 400">
    Returned with code `comment/invalid-query` for invalid values — for example an unknown `include` value, `limit` below `1` or not a whole number, or `sortByReaction` without `sortBy=top`.
  </Accordion>

  <Accordion title="Invalid cursor — 400">
    ```json theme={null}
    {
      "error": "Invalid `cursor`. Pass `pagination.nextCursor` from a previous response unchanged, or leave `cursor` out to start from the beginning.",
      "code": "comment/invalid-cursor"
    }
    ```
  </Accordion>

  <Accordion title="Cursor from a different sort — 400">
    ```json theme={null}
    {
      "error": "This `cursor` was created under a different sort. Send the same `sortBy`, `sortDir` and `sortByReaction` as the request that returned it, or leave `cursor` out to start from the beginning.",
      "code": "comment/cursor-sort-mismatch"
    }
    ```
  </Accordion>

  <Accordion title="Acting as another user — 403">
    Returned when a request authenticated with a user token sends an `actingUserId` other than that user's own ID.

    ```json theme={null}
    {
      "error": "Unauthorized",
      "code": "comment/unauthorized"
    }
    ```
  </Accordion>
</AccordionGroup>

## See Also

* [`useFetchCommentsByUserIdWrapper` hook](/v8/hooks/comments/use-fetch-comments-by-user-id-wrapper)
* [`useFetchCommentsByUserId` hook](/v8/hooks/comments/use-fetch-comments-by-user-id)
* [Comment data model](/v8/data-models/comment)
* [Fetch Many Comments](/v8/api-reference/comments/fetch-many-comments)


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