Skip to main content

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 and deleting comments

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:

ParameterTypeDescription
idstringQuery id. Accepts the UUID or the natural id (ownerId:slug, e.g. admin:regional-sales).

Query Parameters:

ParameterTypeDefaultDescription
sortstring-createdAtSort order
limitinteger-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.

List comments on a queryGET /api/queries/admin:regional-sales/comments
GET /api/queries/{id}/comments is a HAL collection (rel inf:query-comments) embedding inf:comment, filtered to top-level comments (parentId null) and sorted by -createdAt. Each embedded comment carries an inf:comments (./replies) link and an embedded inf:user. {id} accepts the UUID or the natural id (ownerId:slug). Query params are {?sort,limit}. No AI gate and no permission check beyond read access to the query.
Response · 200
{
"_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
}
}
}
]
}
}
Captured from the API examples test suite; ids and timestamps are normalized.
Nested comments

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:

ParameterTypeDescription
idstringQuery 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.

FieldTypeRequiredDescription
messagestringYesComment 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.

Add a comment to a queryPOST /api/queries/admin:regional-sales/comments
POST payload is { message } (joi { message: joi.string() } with stripUnknown, so any other field is dropped). The author (userId) is server-derived from auth, not client-supplied, and queryId comes from the URL. There is NO permission pre-block (any authenticated reader of the query can comment) and NO AI gate. Creating a comment also records a queryAddedComment activity. Responds 201 with a Location header; the body is the RAW Comment row (id, message, public default false, userId, queryId, parentId, mentions, timestamps), NOT HAL-shaped and with no inlined user object.
Request body
{
"message": "This query is running slower than expected. Consider adding an index on the date column."
}
Response · 201
{
"_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
}
Captured from the API examples test suite; ids and timestamps are normalized.
Activity tracking

Creating a comment also records a queryAddedComment activity entry on the Query's activity feed.