Skip to main content
Version: v12

Comments API

The Comments API lets you manage comments on Brinqa records from your own scripts or agents. A comment is a free-text note attached to a single record. You can add a comment, list the comments on one record, list every comment across a whole data model, update or delete your own comments, and search comments by their text.

The API is generic: it works on any record whose data model defines a comment attribute. A data model has at most one comment attribute, so you never have to name it. You identify a record by its data model plus its record id, and the server resolves the comment attribute for you. The examples below use Finding and Ticket records to make this genericity concrete, but the same calls work for SecurityAdvisory, Assessment, CveRecord, or any other commentable model.

Authentication​

The Comments API uses API tokens for authentication. See API Token Authentication for instructions on generating, using, and managing API tokens. Pass the token in the Authorization header using the ApiKey scheme:

Authorization: ApiKey <your-api-token>

The comments endpoints also accept a valid Brinqa UI session, but API token authentication is the supported path for programmatic access.

Endpoints​

OperationMethod and path
Add a commentPOST /v1/api/comments/{model}/{datasetId}
List comments on a recordGET /v1/api/comments/{model}/{datasetId}
List comments across a data modelGET /v1/api/comments/{model}
Update a commentPUT /v1/api/comments/{model}/{datasetId}/{commentId}
Delete a commentDELETE /v1/api/comments/{model}/{datasetId}/{commentId}
Search commentsGET /v1/api/comments/search?q=&dataModel=&page=

The {model} path parameter accepts the data model name (preferred, for example Finding) or the legacy resource name (for example findings) for backward compatibility. {datasetId} and {commentId} are numeric record ids. Use the numeric id, not the hex uid.

When to use which read path​

There are three ways to read comments. Pick the one that matches your intent:

You wantUseEndpoint
The comments on one specific recordList on a recordGET /v1/api/comments/{model}/{datasetId}
Every comment across a data model (no text filter)List across a data modelGET /v1/api/comments/{model}
Comments whose text matches a query (one model or all)SearchGET /v1/api/comments/search?q=<text>

The per-record list returns a flat array and is not paginated. The model-wide list and search return the same paginated object (described in Response shapes), and each result carries a dataset reference so you can navigate back to the parent record. Search requires a non-blank q. If you want an unfiltered model-wide listing, use the list-across-a-data-model endpoint rather than search with a blank query.

Add a comment​

Creates a comment on the record identified by {model} plus {datasetId}. The request body carries only the comment text.

POST /v1/api/comments/{model}/{datasetId}

Headers:

Content-Type: application/json
Authorization: ApiKey <your-api-token>

Request body:

{
"body": "Confirmed exploitable in staging. Escalating to P1."
}
FieldTypeRequiredDescription
bodystringYesThe comment text. Must be non-empty.

Response: 201 Created

The Location header points to the new comment (/v1/api/comments/{model}/{datasetId}/{commentId}). The body is the created comment:

{
"id": 1847262100451,
"body": "Confirmed exploitable in staging. Escalating to P1.",
"dateCreated": "2026-06-11T14:32:10.123Z",
"lastUpdated": "2026-06-11T14:32:10.123Z",
"poster": {
"id": 1847261000001,
"displayName": "Alice Johnson"
}
}

Example (comment on a Finding):

curl -i -X POST 'https://<your-brinqa-instance>/v1/api/comments/Finding/1847261953084' \
-H 'Content-Type: application/json' \
-H 'Authorization: ApiKey <your-api-token>' \
-d '{
"body": "Confirmed exploitable in staging. Escalating to P1."
}'

Example (comment on a Ticket):

curl -i -X POST 'https://<your-brinqa-instance>/v1/api/comments/Ticket/1847261888777' \
-H 'Content-Type: application/json' \
-H 'Authorization: ApiKey <your-api-token>' \
-d '{
"body": "Remediation scheduled for the next maintenance window."
}'
note

Replace <your-brinqa-instance> with the URL of your Brinqa Platform and <your-api-token> with your API token.

List comments on a record​

Returns the comments attached to one record, as a flat array (not paginated). The caller must have read access to the record.

GET /v1/api/comments/{model}/{datasetId}

Headers:

Authorization: ApiKey <your-api-token>

Response: 200 OK

[
{
"id": 1847262100451,
"body": "Confirmed exploitable in staging. Escalating to P1.",
"dateCreated": "2026-06-11T14:32:10.123Z",
"lastUpdated": "2026-06-11T14:32:10.123Z",
"poster": { "id": 1847261000001, "displayName": "Alice Johnson" }
},
{
"id": 1847262100899,
"body": "Patch scheduled for the next maintenance window.",
"dateCreated": "2026-06-11T15:00:00.000Z",
"lastUpdated": "2026-06-11T15:00:00.000Z",
"poster": { "id": 1847261000002, "displayName": "Bob Smith" }
}
]

Example:

curl 'https://<your-brinqa-instance>/v1/api/comments/Finding/1847261953084' \
-H 'Authorization: ApiKey <your-api-token>'

List comments across a data model​

Returns every comment attached to records of the given data model, scoped to records the caller can read. Use this when you want all comments on, say, Findings or Tickets without filtering by text. The response is paginated and uses the same shape as Search, without the text filter.

GET /v1/api/comments/{model}?page=

Query parameters:

ParameterTypeRequiredDescription
pageintegerNoZero-based page number. Defaults to 0.

Headers:

Authorization: ApiKey <your-api-token>

Response: 200 OK

{
"results": [
{
"id": 1847262100451,
"body": "Confirmed exploitable in staging. Escalating to P1.",
"dateCreated": "2026-06-11T14:32:10.123Z",
"lastUpdated": "2026-06-11T14:32:10.123Z",
"poster": { "id": 1847261000001, "displayName": "Alice Johnson" },
"dataset": {
"id": 1847261953084,
"dataModel": "Finding",
"displayValue": "CVE-2026-0001 on web-prod-01"
}
}
],
"totalRows": 1,
"page": 0,
"pageSize": 25,
"nextPage": null,
"truncated": false
}

Results are ordered by dateCreated descending (newest first). See Response shapes for the pagination fields and the truncated flag.

Example (all comments on Findings):

curl 'https://<your-brinqa-instance>/v1/api/comments/Finding?page=0' \
-H 'Authorization: ApiKey <your-api-token>'

Example (all comments on Tickets, second page):

curl 'https://<your-brinqa-instance>/v1/api/comments/Ticket?page=1' \
-H 'Authorization: ApiKey <your-api-token>'

Update a comment​

Replaces the body of a comment you created. Only the comment's author may update it.

PUT /v1/api/comments/{model}/{datasetId}/{commentId}

Headers:

Content-Type: application/json
Authorization: ApiKey <your-api-token>

Request body:

{
"body": "Confirmed exploitable in staging. Escalating to P1. Owner notified."
}
FieldTypeRequiredDescription
bodystringYesThe replacement comment text. Must be non-empty.

Response: 200 OK

Returns the persisted comment. dateCreated is preserved and lastUpdated is refreshed.

{
"id": 1847262100451,
"body": "Confirmed exploitable in staging. Escalating to P1. Owner notified.",
"dateCreated": "2026-06-11T14:32:10.123Z",
"lastUpdated": "2026-06-11T14:35:22.456Z",
"poster": { "id": 1847261000001, "displayName": "Alice Johnson" }
}

Example:

curl -X PUT 'https://<your-brinqa-instance>/v1/api/comments/Finding/1847261953084/1847262100451' \
-H 'Content-Type: application/json' \
-H 'Authorization: ApiKey <your-api-token>' \
-d '{
"body": "Confirmed exploitable in staging. Escalating to P1. Owner notified."
}'

Delete a comment​

Deletes a comment you created. Only the comment's author may delete it.

DELETE /v1/api/comments/{model}/{datasetId}/{commentId}

Headers:

Authorization: ApiKey <your-api-token>

Response: 204 No Content with an empty body.

Example:

curl -i -X DELETE 'https://<your-brinqa-instance>/v1/api/comments/Ticket/1847261888777/1847262100899' \
-H 'Authorization: ApiKey <your-api-token>'

Search comments​

Returns comments whose body text matches a query, scoped to records the caller can read. Supply dataModel to search within one model (faster), or omit it to search across all accessible records. Use search when you are looking for comments by content. To list every comment on a model with no text filter, use List comments across a data model instead.

GET /v1/api/comments/search?q=&dataModel=&page=

Query parameters:

ParameterTypeRequiredDescription
qstringYesFree-text query, 1 to 1000 characters. A blank q returns 400.
dataModelstringNoData model name to scope the search (for example Finding). Omit for a cross-model search.
pageintegerNoZero-based page number. Defaults to 0.

Headers:

Authorization: ApiKey <your-api-token>

Response: 200 OK

Same paginated shape as the model-wide listing. Each result carries a dataset reference (id, dataModel, displayValue) identifying the parent record:

{
"results": [
{
"id": 1847262100451,
"body": "Marked as a false positive after manual review.",
"dateCreated": "2026-06-11T14:32:10.123Z",
"lastUpdated": "2026-06-11T14:32:10.123Z",
"poster": { "id": 1847261000001, "displayName": "Alice Johnson" },
"dataset": {
"id": 1847261953084,
"dataModel": "Finding",
"displayValue": "CVE-2026-0001 on web-prod-01"
}
}
],
"totalRows": 1,
"page": 0,
"pageSize": 25,
"nextPage": null,
"truncated": false
}

Example (cross-dataset search across all models):

curl 'https://<your-brinqa-instance>/v1/api/comments/search?q=false%20positive' \
-H 'Authorization: ApiKey <your-api-token>'

Example (search scoped to one model):

curl 'https://<your-brinqa-instance>/v1/api/comments/search?q=patch%20deferred&dataModel=Ticket&page=0' \
-H 'Authorization: ApiKey <your-api-token>'

Response shapes​

Comment object​

Returned by create, update, the per-record list, the model-wide list, and search.

FieldTypeDescription
idintegerThe comment id.
bodystringThe comment text.
dateCreatedstringWhen the comment was created (ISO 8601, UTC).
lastUpdatedstringWhen the comment was last updated (ISO 8601, UTC).
posterobjectThe comment's author: { "id": integer, "displayName": string }.
datasetobjectModel-wide list and search only. A reference to the parent record: { "id": integer, "dataModel": string, "displayValue": string }.

Paginated list​

Returned by the model-wide list and search. The per-record list is a flat array and does not use this envelope.

FieldTypeDescription
resultsarrayThe comment objects for this page, ordered by dateCreated descending.
totalRowsintegerTotal comments matched across all pages (capped, see truncated).
pageintegerThe current zero-based page number.
pageSizeintegerPage size (fixed at 25).
nextPageintegerThe next page number, or null on the last page.
truncatedbooleantrue when the result set hit the server-side cap and more comments may exist than totalRows reports. Narrow the query (or scope by dataModel) to see the rest.

Permissions and access control​

  • Per-record operations (create, list-on-record, update, delete) require read access to the target record. A caller without read access to a record receives 404, not 403, so the API does not reveal whether a record exists.
  • Update and delete additionally require that the caller is the author of the comment. A non-author receives 403.
  • Model-wide list and search enforce per-record access control: comments on records the caller cannot read are silently excluded from the results (no error).

Rate limits​

Each operation is independently rate limited. If you exceed a limit, the API returns 429 Too Many Requests. Wait for the interval given in the Retry-After response header before retrying.

Error handling​

HTTP StatusMeaningCommon cause
200 OKRead or update succeeded.Normal response for list, model-wide list, search, and update.
201 CreatedComment created.Normal response for add. The Location header holds the new comment URL.
204 No ContentComment deleted.Normal response for delete.
400 Bad RequestInvalid request body or parameters.A blank body on add or update; a blank q or q longer than 1000 characters on search; a page number out of range on the model-wide list or search.
401 UnauthorizedAuthentication failed.Missing, invalid, expired, or revoked API token.
403 ForbiddenNot permitted.The caller is not the author of the comment being updated or deleted, or lacks permission to add a comment on the record.
404 Not FoundTarget not found, or not visible.Unknown data model; a data model with no comment attribute; an unknown dataModel on search; an unknown comment id; or a record the caller cannot read (returned as 404, not 403).
422 Unprocessable EntityMalformed request body.The request body is not valid JSON.
429 Too Many RequestsRate limit exceeded.Too many requests in a short period. Wait for the Retry-After interval and retry.

Manage comments from an AI client (MCP tools)​

The same comment operations are available to MCP-compatible AI clients (Claude Desktop, Claude Code CLI, GitHub Copilot in VS Code, Goose, and others) through the BrinqaIQ MCP integration. For client setup and authentication, see BrinqaIQ MCP. These tools inherit the permissions of the user account tied to your API token.

BrinqaIQ exposes five comment tools. Like the REST API, they are generic across data models, so the examples below span Findings and Tickets.

ToolWhat it doesExample prompt
comments.addAdd a comment to one record."Add a comment to Finding 1847261953084 saying 'investigating, ETA Friday'."
comments.listList comments, on one record or across a whole data model."Show all comments on Ticket 1847261888777." and "Show all comments on Findings."
comments.updateEdit the text of an existing comment."Update comment 1847262100451 on that Finding to add 'owner notified'."
comments.deleteRemove a comment."Delete comment 1847262100899 on Ticket 1847261888777."
comments.searchFind comments by their text, across one model or all records."Search Ticket comments mentioning 'patch deferred'." and "Find any comments that mention 'false positive'."

A few behaviors worth knowing:

  • comments.list works at two levels. Give it a record id to list one record's comments, or omit the record id to list every comment across the data model (paginated, so the agent shows one page and you can ask for more). For example, "show comments on Finding 1847261953084" lists one record, while "show all comments on Findings" lists the whole model.
  • comments.search matches comment text, not records, and can run across every data model or be scoped to one (for example "search Ticket comments for 'patch deferred'" versus "find all comments mentioning 'audit'"). Reach for search when you are looking by content. Use comments.list without a record id when you want everything on a model with no text filter.
  • Update and delete ask before they act. comments.update and comments.delete change stored data, so the client shows an in-chat confirmation card summarizing the change and waits for you to confirm before the operation runs.