Search comments
Search comments with a structured filter AST, full-text search, sorting, and cursor pagination.
Two modes (combinable)
- Filter mode — pass a structured
queryAST (and/orsort) and the endpoint returns comments matching the filter, ordered bysort(defaultcreatedAt:desc). Same shape as/v2/posts/search,/v2/conversations/search,/v2/companies/search,/v2/contacts/search. - Search mode — pass a top-level
searchstring and the endpoint runs a hybrid full-text + vector search over commentcontent, returning matches ranked by relevance. Optional: combine withqueryto constrain the search to a post / changelog / author / time window, and/orsortto override relevance ranking with chronological order.
{
"search": "dark mode feedback",
"query": {
"operator": "AND",
"value": [
{ "field": "postId", "operator": "=", "value": "507f1f77bcf86cd799439011" }
]
},
"limit": 20
}search is server-managed: no operators, no field selection, no special syntax — same plain-text contract as /v2/posts/search. The string must be 1–500 characters.
Structured query AST
Each clause has the shape { field, operator, value }. You can pass a single clause or wrap up to 15 in a top-level AND group. To list every comment a contact has authored:
{
"query": { "field": "authorId", "operator": "=", "value": "507f1f77bcf86cd799439011" },
"sort": "createdAt:desc",
"limit": 100
}Top-level OR groups and nested groups are not supported in this version.
Supported fields and operators
Field names are camelCase, matching the rest of the v2 public API. The other v2 search endpoints (posts, contacts, companies, conversations) shipped earlier with snake_case field names and continue to accept those for back-compat; comments search is greenfield and ships with camelCase only.
| Field | Type | Operators |
|---|---|---|
authorId | string (user id) | =, !=, IN, NIN |
postId | id or null (submission) | =, !=, IN, NIN (use null for changelog-only comments) |
changelogId | id or null | =, !=, IN, NIN (use null for post-only comments) |
parentCommentId | id or null | =, !=, IN, NIN (use null for root comments, non-null for replies) |
isPrivate | boolean | =, != |
inReview | boolean | =, != |
createdAt | unix seconds | =, !=, >, <, >=, <= |
upvotes, score, confidenceScore | number | =, !=, >, <, >=, <= |
Use the top-level search field for full-text search across comment content (see "Search mode" above). The clause-level operators ~, !~, ^, $ are reserved for future use and currently return 400.
A filter-mode query (no search) consisting only of != or NIN clauses on unbounded fields is rejected with query_too_broad to prevent full-org scans. Combine the negation with at least one positive clause (=, IN, >, <) instead. Boolean fields (isPrivate, inReview) are bounded so a standalone negation on them is allowed. Search mode (with search set) relaxes this — the FTS query itself acts as the positive constraint.
Sort
Allowed values:
createdAt:desc(default in filter mode),createdAt:asc— newest / oldest firstconfidenceScore:desc(the dashboard's "Best" view),confidenceScore:asc(low-confidence first, useful for moderation)score:desc— raw upvotes − downvotes ("Top")
Numeric counters (upvotes, score, confidenceScore) remain available as filter fields with the full range of operators; only the sort axes above are surfaced to keep the cursor-pagination contract small. score:asc and upvotes (both directions) are deliberately not exposed: upvotes:desc is identical to score:desc for the vast majority of comments (no downvotes), and "most-downvoted-first" / "least-upvoted-first" have no product use case.
When search is set, results are ranked by relevance unless sort is also set, in which case the matching comments are returned in the requested order. The chosen sort axis (or relevance) is encoded in the cursor; switching sort (or toggling search on/off) mid-pagination returns 400 invalid_cursor. Restart pagination without a cursor when changing the sort or search shape.
Pagination
Cursor-based, limit between 1 and 100 (default 10). In filter mode, totalCount is approximate and capped at 5000; totalCountCapped is true when the real count may be higher. In search mode, totalCount reflects the matching survivor set after the AST filter and is capped at 200 (the Turbopuffer top-K).
Server-side guards
These visibility rules are always applied and CANNOT be widened via the AST:
- Callers without the
view_comments_privatepermission can only see public comments. Sending{ field: "isPrivate", operator: "=", value: true }as such a caller returns an empty result, NOT a 403 — the security floor wins. - Callers without the
moderate_commentspermission can only see in-review comments they authored themselves.inReviewqueries from such callers are intersected with the authored-by-self constraint. - Spam comments (
isSpam: true) are NOT excluded — this matches the legacyGET /v2/commentsbehavior. If you want to exclude spam, filter on theisSpamfield (NOT exposed today; track follow-up).
Response
Returns a standard list envelope with comment rows identical to GET /v2/comments/{id}.
Version Availability
This endpoint is only available in API version 2026-01-01.nova and newer.
Body
An opaque cursor for pagination. Use the nextCursor value from a previous response to fetch the next page of results.
512eyJpZCI6IjUwN2YxZjc3YmNmODZjZDc5OTQzOTAxMSJ9A limit on the number of objects to be returned, between 1 and 100.
1 <= x <= 10010Structured filter AST. Either a single filter clause or one top-level AND group (max 15 clauses). Top-level OR groups are not yet supported.
Plain-text full-text search across comment content. Server-managed (hybrid BM25 + vector, semanticRatio 0.5) — no operators, no field selection. When search is set, results are ranked by relevance unless sort is also set, in which case the matching comments are returned in the requested order. Combine with query to constrain the search to a post / changelog / author / time window.
1 - 500dark mode feedbackSort field + direction. Defaults to createdAt:desc in filter mode and to relevance in search mode. The chosen sort axis is encoded in the cursor; switching sort (or toggling search on/off) mid-pagination returns 400 invalid_cursor.
createdAt:desc, createdAt:asc, confidenceScore:desc, confidenceScore:asc, score:desccreatedAt:descResponse
Success
Cursor for fetching the next page (null if no more results)
eyJpZCI6IjUwN2YxZjc3YmNmODZjZDc5OTQzOTAxMSJ9Total number of comments matching the query, capped at 5000 in filter mode and 200 (the Turbopuffer top-K) in search mode. When at the cap, totalCountCapped is true and the value is exactly the cap.
42More in Comments
GETList commentsPOSTCreate a new commentGETGet a comment by IDPATCHUpdate a commentStill need help? Ask the team