Comments
The Query module owns exactly two comment routes: listing the top-level comments
on a Query and adding a new comment. Both resolve the Query through its
read_access scope, so a caller only needs to be able to read the Query.
Neither route is AI-gated, and neither carries a permission pre-block: any
authenticated user who can read the Query may comment on it.
The comment author is server-derived from the authenticated user, and the Query id comes from the URL. Clients never supply the author or the Query id in the payload.
Editing (PUT) and deleting (DELETE) an individual comment, and listing a
comment's replies, are served by the separate Comment module under
/api/comments/{id}, not by the Query module. They are documented with the
Comment API, not on this page.
GET /api/queries/{id}/comments
List the top-level comments on a Query. The collection is filtered to top-level
comments (parentId is null) and sorted by -createdAt.
Authentication: Required (read access to the Query)
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | string | Query id. Accepts the UUID or the natural id (ownerId:slug, e.g. admin:regional-sales). |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
sort | string | -createdAt | Sort order |
limit | integer | - | Results per page |
Response:
A HAL collection (rel inf:query-comments) embedding inf:comment. Each
embedded comment carries an inf:comments link to its replies
(/api/comments/{id}/replies) and an embedded inf:user for the author. The
envelope reports start, count, and total.
{
"_links": {
"self": {
"href": "https://informer.example.com/api/queries/admin%3Aregional-sales/comments?sort=-createdAt&limit=0"
}
},
"start": 0,
"count": 1,
"total": 1,
"_embedded": {
"inf:comment": [
{
"_links": {
"self": {
"href": "https://informer.example.com/api/comments/00000000-0000-4000-8000-000000000001"
},
"inf:comments": {
"href": "https://informer.example.com/api/comments/00000000-0000-4000-8000-000000000001/replies"
}
},
"permissions": {
"edit": true,
"delete": true
},
"id": "00000000-0000-4000-8000-000000000001",
"message": "Updated the date filter to use a parameter instead of a hardcoded value.",
"public": false,
"userId": "admin",
"datasetId": null,
"datasourceId": null,
"reportId": null,
"queryId": "00000000-0000-4000-8000-000000000002",
"teamId": null,
"jobId": null,
"templateId": null,
"assistantId": null,
"libraryId": null,
"mentions": null,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"tenant": "acme",
"parentId": null,
"_embedded": {
"inf:user": {
"_links": {
"self": {
"href": "https://informer.example.com/api/users/admin"
},
"inf:memberships": {
"href": "https://informer.example.com/api/users/admin/memberships"
},
"inf:avatar-upload": {
"href": "https://informer.example.com/api/users/admin/_upload/{uploadId}/avatar-upload",
"templated": true
},
"inf:password": {
"href": "https://informer.example.com/api/users/admin/password"
},
"inf:feed": {
"href": "https://informer.example.com/api/users/admin/feed"
},
"inf:viewed-feed": {
"href": "https://informer.example.com/api/users/admin/_markFeedViewed"
},
"inf:superuser": {
"href": "https://informer.example.com/api/users/admin/superuser"
}
},
"permissions": {
"changeDomain": false,
"changeProfile": true,
"changePassword": true,
"delete": false,
"edit": true,
"reassign": true,
"superuser": true,
"enable": true,
"changeTheme": true,
"lock": true,
"setGlobalPermissions": true,
"manageLogin": true
},
"domain": "local",
"username": "admin",
"displayName": "acme Administrator",
"familyName": "Administrator",
"givenName": "acme",
"middleName": null,
"email": null,
"data": null,
"superuser": true,
"timezone": "America/New_York",
"settings": {
"log": {
"log": false,
"info": false,
"warn": false,
"debug": false,
"error": true,
"remote": false
}
},
"enabled": true,
"source": null,
"sourceId": null,
"lastViewedFeed": null,
"tenant": "acme",
"globalPermissions": {
"ai": false,
"jobCreation": true,
"viewAllTeams": true,
"viewAllUsers": true,
"painlessScriptCreation": true
},
"userFields": {},
"locked": false,
"lockedAt": null,
"loginAttempts": 0,
"passwordSetAt": "2026-01-15T16:20:00.000Z",
"passwordExpiresAt": "2026-01-15T16:20:00.000Z",
"forgotPasswordRequestTime": null,
"mfa": null,
"mfaConfig": {},
"aiMessage": null,
"aiConsent": false,
"hasSharedDatasources": false,
"createdAt": "2026-01-15T16:20:00.000Z",
"updatedAt": "2026-01-15T16:20:00.000Z",
"initials": "EA",
"colorIndex": 4,
"avatarColor": {
"background": "#81C784",
"text": "#1B5E20"
},
"managesPassword": true
}
}
}
]
}
}
This endpoint returns only top-level comments (where parentId is null). To
get replies, follow the inf:comments link on each comment.
POST /api/queries/{id}/comments
Add a comment to a Query.
Authentication: Required (read access to the Query)
Pre-blocks: query.lookup (read_access scope). There is no permission
pre-block and no AI gate.
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
id | string | Query id. Accepts the UUID or the natural id (ownerId:slug). |
Request Body:
The payload is validated against { message: joi.string() } with
stripUnknown, so any other field (including userId, username, or queryId)
is silently dropped. The author is taken from the authenticated user and the
Query id from the URL.
| Field | Type | Required | Description |
|---|---|---|---|
message | string | Yes | Comment text |
Example Request:
{
"message": "This query is running slower than expected. Consider adding an index on the date column."
}
Response:
Responds 201 Created with a Location header. The body is the created Comment
row (id, message, public defaulting to false, userId, queryId,
parentId, mentions, and timestamps). It does not inline a user object.
{
"message": "This query is running slower than expected. Consider adding an index on the date column."
}
{
"_links": {
"self": {
"href": "https://informer.example.com/api/comments/00000000-0000-4000-8000-000000000001"
}
},
"permissions": {
"edit": true,
"delete": true
},
"id": "00000000-0000-4000-8000-000000000001",
"public": false,
"tenant": "acme",
"message": "This query is running slower than expected. Consider adding an index on the date column.",
"queryId": "00000000-0000-4000-8000-000000000002",
"userId": "admin",
"updatedAt": "2026-01-15T16:20:00.000Z",
"createdAt": "2026-01-15T16:20:00.000Z",
"mentions": null,
"teamId": null,
"_altid": null,
"datasetId": null,
"datasourceId": null,
"reportId": null,
"jobId": null,
"parentId": null,
"templateId": null,
"assistantId": null,
"libraryId": null
}
Creating a comment also records a queryAddedComment activity entry on the
Query's activity feed.