Skip to content

Comments API ​

Comments are threaded discussions on issues and epics. A comment on an issue notifies the issue's watchers and any @mentioned users. A comment on an epic notifies only @mentioned users, and the parent comment's author for a reply: epics have no watchers.

Permissions ​

ActionRequired PermissionScope
ListIssues: Read or Epics: ReadThe Read permission of the comment's subject, in accessible projects
CreateComments: CreateOn issues and epics within accessible projects
UpdateComments: Update (Own/All)Own: only your comments. All: any comment
DeleteComments: Delete (Own/All)Own: only your comments. All: any comment
Pin / UnpinIssues: Update or Epics: UpdatePinning curates the subject, so it follows the subject's Update permission — not comment authorship
Like / UnlikeComments: ReadAny project member who can see the comment can like it — including the comment's own author

Admins and project owners bypass all permission checks for project-scoped resources.

Endpoints ​

Every endpoint below answers for an epic too: replace issues/{issueId} with epics/{epicId}, for example GET /api/projects/{projectId}/epics/{epicId}/comments. A comment's commentable_type says which subject it belongs to: issues or epics.

MethodEndpointDescription
GET/api/projects/{projectId}/issues/{issueId}/commentsList comments
POST/api/projects/{projectId}/issues/{issueId}/commentsCreate a comment
PUT/api/projects/{projectId}/issues/{issueId}/comments/{commentId}Update a comment
DELETE/api/projects/{projectId}/issues/{issueId}/comments/{commentId}Delete a comment
POST/api/projects/{projectId}/issues/{issueId}/comments/{commentId}/pinPin a comment
DELETE/api/projects/{projectId}/issues/{issueId}/comments/{commentId}/pinUnpin a comment
POST/api/projects/{projectId}/issues/{issueId}/comments/{commentId}/likeToggle the current user's like on a comment

Threaded Replies ​

Comments support one level of threading. A reply is a comment with a parent_id pointing to a root comment on the same issue or epic.

  • Max depth: 1. Replies cannot themselves be replied to — parent_id must reference a root comment (one with parent_id: null). Passing a parent_id that points to an existing reply returns 422.
  • Cascade delete. Deleting a root comment also deletes all its replies.
  • Reply notifications. Creating a reply notifies the parent comment's author (unless they are the replier, or already notified via @mention).

Create Comment ​

POST /api/projects/{projectId}/issues/{issueId}/comments

Request Fields ​

FieldTypeRequiredDescription
contentstringYesComment text, max 10,000 characters. Supports Markdown and @mentions.
parent_idintegerNoID of the root comment to reply to. Must be a root comment (not a reply) on the same issue or epic. Omit for top-level comments.
bash
curl -X POST https://{tenant}.kendo.dev/api/projects/1/issues/42/comments \
  -H "Authorization: Bearer your-token" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "The pagination is working, but we should add a `per_page` parameter. @jasper what do you think?"
  }'
bash
curl -X POST https://{tenant}.kendo.dev/api/projects/1/issues/42/comments \
  -H "Authorization: Bearer your-token" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "Agreed — I can add that in the follow-up.",
    "parent_id": 10
  }'
json
{
  "id": 11,
  "content": "Agreed — I can add that in the follow-up.",
  "parent_id": 10,
  "is_pinned": false,
  "user_id": 2,
  "commentable_type": "issues",
  "commentable_id": 42,
  "created_at": "2026-03-13T14:05:00.000000Z",
  "liker_ids": []
}

Update Comment ​

PUT /api/projects/{projectId}/issues/{issueId}/comments/{commentId}

Request Fields ​

FieldTypeRequiredDescription
contentstringYesUpdated comment text, max 10,000 characters
bash
curl -X PUT https://{tenant}.kendo.dev/api/projects/1/issues/42/comments/10 \
  -H "Authorization: Bearer your-token" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "The pagination is working. Added a `per_page` parameter in the follow-up PR."
  }'
json
{
  "id": 10,
  "content": "The pagination is working. Added a `per_page` parameter in the follow-up PR.",
  "parent_id": null,
  "is_pinned": false,
  "user_id": 1,
  "commentable_type": "issues",
  "commentable_id": 42,
  "created_at": "2026-03-13T14:00:00.000000Z",
  "liker_ids": []
}

Delete Comment ​

DELETE /api/projects/{projectId}/issues/{issueId}/comments/{commentId}

Returns 204 No Content on success.

bash
curl -X DELETE https://{tenant}.kendo.dev/api/projects/1/issues/42/comments/10 \
  -H "Authorization: Bearer your-token"

Pin / Unpin Comment ​

Each issue or epic can have at most one pinned comment, surfaced at the top of the comment section regardless of pagination. Pinning a different comment unpins the previous one. Pinning requires Issues: Update on an issue and Epics: Update on an epic — it curates the subject, so comment authorship alone does not grant it.

POST /api/projects/{projectId}/issues/{issueId}/comments/{commentId}/pin — pin DELETE /api/projects/{projectId}/issues/{issueId}/comments/{commentId}/pin — unpin

Both return 200 OK with the updated comment (is_pinned reflects the new state).

bash
curl -X POST https://{tenant}.kendo.dev/api/projects/1/issues/42/comments/10/pin \
  -H "Authorization: Bearer your-token"
bash
curl -X DELETE https://{tenant}.kendo.dev/api/projects/1/issues/42/comments/10/pin \
  -H "Authorization: Bearer your-token"
json
{
  "id": 10,
  "content": "Decision: we ship the per_page parameter in this PR.",
  "parent_id": null,
  "is_pinned": true,
  "user_id": 1,
  "commentable_type": "issues",
  "commentable_id": 42,
  "created_at": "2026-03-13T14:00:00.000000Z",
  "liker_ids": []
}

Like / Unlike Comment ​

Liking is a single toggle — one request likes an unliked comment, the next unlikes it. Unlike pinning, any number of members can like the same comment, and a comment's own author can like it too. Both root comments and replies can be liked.

POST /api/projects/{projectId}/issues/{issueId}/comments/{commentId}/like — toggle

Returns 200 OK with the updated comment. liker_ids lists the IDs of every user who currently likes it, including the caller after a like.

bash
curl -X POST https://{tenant}.kendo.dev/api/projects/1/issues/42/comments/10/like \
  -H "Authorization: Bearer your-token"
json
{
  "id": 10,
  "content": "Decision: we ship the per_page parameter in this PR.",
  "parent_id": null,
  "is_pinned": true,
  "user_id": 1,
  "commentable_type": "issues",
  "commentable_id": 42,
  "created_at": "2026-03-13T14:00:00.000000Z",
  "liker_ids": [2]
}

See Also ​