Skip to main content

Comments API

The Comments API attaches free-text comments to a specific version of an asset. Comments support asset review workflows: a reviewer records an observation against the version they inspected, and the comment stays bound to that version as the asset evolves.

Authorization

All endpoints require a valid JWT token in the Authorization header. Comment endpoints enforce Casbin authorization against the owning asset using the asset object type — there is no separate comment object type. A caller who can read an asset can read its comments, and a caller who can write an asset can add comments to it.


Concepts

  • Comment identity: A comment is identified by the asset it belongs to plus a composite assetVersionId:commentId key. Both halves are supplied by the caller as a single colon-joined path parameter.
  • Ownership: The user who creates a comment becomes its owner. Only the owner can edit or delete it, regardless of their asset permissions.
  • Soft delete: A deleted comment is moved to a parallel #deleted partition rather than removed. It stops appearing in the asset's comment listings.
  • Version scope: Every comment is attached to an asset version. Listing by version returns the comments recorded against that version alone.

Comment fields

FieldTypeDescription
assetIdstringAsset the comment belongs to.
assetVersionId:commentIdstringComposite identifier: the asset version and the comment ID, colon-joined.
commentBodystringComment text.
commentOwnerIDstringUser ID of the comment's creator.
commentOwnerUsernamestringDisplay identity of the creator.
dateCreatedstringISO 8601 creation timestamp.
dateEditedstringISO 8601 timestamp of the last edit. Present only on an edited comment.

Endpoints

List comments for an asset

GET /comments/assets/{assetId}

Retrieves every comment on an asset, across all of its versions, newest first.

Request Parameters:

ParameterLocationTypeRequiredDescription
assetIdpathstringYesAsset identifier.
maxItemsqueryintegerNoMaximum number of comments to return.
pageSizequeryintegerNoNumber of comments per page.
startingTokenquerystringNoPagination token.

Response:

{
"message": [
{
"assetId": "asset-001",
"assetVersionId:commentId": "2:c1a2b3c4-d5e6-7890-abcd-ef1234567890",
"commentBody": "The north facade needs a higher-resolution texture.",
"commentOwnerID": "user@example.com",
"commentOwnerUsername": "user@example.com",
"dateCreated": "2026-03-15T10:30:00.000000Z"
}
]
}

message is the comment array itself. The response carries no continuation token, so maxItems bounds the whole result set for a call rather than opening a page sequence.

Error Responses:

StatusDescription
400Invalid assetId, or an assetId that resolves to more than one live asset.
403Not authorized to read this asset.
404Asset not found.
405Method not allowed.
500Internal server error.

List comments for an asset version

GET /comments/assets/{assetId}/assetVersionId/{assetVersionId}

Retrieves the comments recorded against one version of an asset, newest first.

Request Parameters:

ParameterLocationTypeRequiredDescription
assetIdpathstringYesAsset identifier.
assetVersionIdpathstringYesAsset version identifier.
maxItemsqueryintegerNoMaximum number of comments to return.
pageSizequeryintegerNoNumber of comments per page.
startingTokenquerystringNoPagination token.

Response:

Same shape as List comments for an asset, restricted to the named version.

Error Responses:

StatusDescription
400Invalid assetId, or an assetId that resolves to more than one live asset.
403Not authorized to read this asset.
404Asset not found.
500Internal server error.

Get a comment

GET /comments/assets/{assetId}/assetVersionId:commentId/{assetVersionId:commentId}

Retrieves a single comment.

Request Parameters:

ParameterLocationTypeRequiredDescription
assetIdpathstringYesAsset identifier.
assetVersionId:commentIdpathstringYesAsset version and comment ID, colon-joined (for example 2:c1a2b3c4).

Response:

{
"message": {
"assetId": "asset-001",
"assetVersionId:commentId": "2:c1a2b3c4-d5e6-7890-abcd-ef1234567890",
"commentBody": "The north facade needs a higher-resolution texture.",
"commentOwnerID": "user@example.com",
"commentOwnerUsername": "user@example.com",
"dateCreated": "2026-03-15T10:30:00.000000Z"
}
}

A comment that does not exist returns 200 with an empty message object rather than a 404.

Error Responses:

StatusDescription
400Invalid assetId or comment ID, or a malformed composite path parameter.
403Not authorized to read this asset.
404Asset not found.
500Internal server error.

Add a comment

POST /comments/assets/{assetId}/assetVersionId:commentId/{assetVersionId:commentId}

Adds a comment to a version of an asset. The caller supplies the comment ID as the second half of the composite path parameter, and becomes the comment's owner.

Request Parameters:

ParameterLocationTypeRequiredDescription
assetIdpathstringYesAsset identifier.
assetVersionId:commentIdpathstringYesAsset version and the new comment's ID, colon-joined.

Request Body:

FieldTypeRequiredDescription
commentBodystringYesComment text, up to 16,384 characters.
{
"commentBody": "The north facade needs a higher-resolution texture."
}

Response:

{
"message": "Succeeded"
}

Error Responses:

StatusDescription
400Missing or invalid path parameters, a missing or over-length commentBody, a comment that already exists, or an assetId that resolves to more than one live asset.
403Not authorized to write this asset.
404Asset not found.
500Internal server error.

Edit a comment

PUT /comments/assets/{assetId}/assetVersionId:commentId/{assetVersionId:commentId}

Replaces a comment's text and records a dateEdited timestamp. Only the comment's owner can edit it.

Request Parameters:

ParameterLocationTypeRequiredDescription
assetIdpathstringYesAsset identifier.
assetVersionId:commentIdpathstringYesAsset version and comment ID, colon-joined.

Request Body:

FieldTypeRequiredDescription
commentBodystringYesReplacement comment text, up to 16,384 characters.

Response:

{
"message": "Succeeded"
}

Error Responses:

StatusDescription
400Missing or invalid path parameters, or a missing or over-length commentBody.
403Not authorized to write this asset, or the caller does not own the comment.
404Asset not found, or the comment does not exist.
500Internal server error.

Delete a comment

DELETE /comments/assets/{assetId}/assetVersionId:commentId/{assetVersionId:commentId}

Soft-deletes a comment. Only the comment's owner can delete it.

Request Parameters:

ParameterLocationTypeRequiredDescription
assetIdpathstringYesAsset identifier.
assetVersionId:commentIdpathstringYesAsset version and comment ID, colon-joined.

Response:

{
"message": "Succeeded"
}

Error Responses:

StatusDescription
400Missing path parameters, or a malformed composite path parameter.
403Not authorized to delete on this asset, or the caller does not own the comment.
404Asset not found, or the comment does not exist.
500Internal server error.