Skip to content

List comments

GET/api/v2/workspaces/{slug}/projects/{project_id}/work-items/{work_item_id}/comments/

Return the comments on one work item. Comments are scoped to their parent work item, so this is the only way to read a work item's discussion — reach for it when rendering a work item detail view or mirroring a thread into another system.

Path Parameters

slug:requiredstring

The workspace slug. It appears in your Plane URLs — in https://app.plane.so/my-team/projects/, the slug is my-team.

project_id:requiredstring (uuid)

The project the work item belongs to.

work_item_id:requiredstring (uuid)

The work item whose comments you want. Comments never span work items, so this narrows the result set by itself.

Query Parameters

Filters

access:optionalstring

Return only comments with this visibility.

  • INTERNAL — visible to the project team
  • EXTERNAL — marked as visible outside the team
external_id:optionalstring

Return comments carrying this identifier from your system. external_id is not a unique key, so this can match more than one comment — pair it with external_source and handle a multi-row result.

external_source:optionalstring

Return comments that came from this system, for example github or zendesk.

Search

search:optionalstring

Match comments against their plain-text body (comment_stripped), so HTML markup in comment_html never affects whether a term hits.

Ordering

order_by:optionalstring

Field to sort by. Prefix with - for descending. Send it explicitly whenever order matters — a thread you render should not depend on the server's unstated default.

  • created_at — oldest first
  • -created_at — newest first
  • id
  • -id

Pagination

per_page:optionalinteger

Page size. Defaults to 50, maximum 200.

offset:optionalinteger

Number of rows to skip from the start of the result set. Maximum 10000 — for deeper traversal switch to cursor pagination.

paginate:optionalstring

Set to cursor to opt into the COUNT-free keyset envelope instead of the default offset envelope. The response then carries next_cursor and has_more; send the value of next_cursor back as ?cursor= to fetch the next page. See Pagination for the full envelope.

count:optionalboolean

Defaults to true. Set to false to skip the COUNT(*) and omit total_count from the offset envelope.

access is validated, order_by is not

access is checked against its allowed values — an unrecognized value is rejected as a 400 validation_error, so you never get a silently empty list back. order_by is not checked: an unrecognized value falls back to the default ordering, so check your spelling there because a typo shows up as an unexpected sort order rather than an error.

Scopes

projects.work_items.comments:read

Errors

StatusCodeCause
401unauthorizedMissing or invalid credentials.
403forbiddenYour role or token scope can't read this work item.
404resource_not_foundNo such workspace, project, or work item, or it's outside your tenant.
429rate_limitedThrottled. Honor the Retry-After header before retrying.
List comments
bash
curl -X GET \
  "https://api.plane.so/api/v2/workspaces/my-team/projects/4af68566-94a4-4eb3-94aa-50dc9427067b/work-items/8f4c2b1e-0d3a-4f7b-9c21-6e5a8b7d4f13/comments/?access=INTERNAL&per_page=50" \
  -H "X-Api-Key: $PLANE_API_KEY"
Response200
json
{
  "data": [
    {
      "id": "c1f7a3d9-2b64-4f80-9c1a-3d5e8b2a6c47",
      "work_item_id": "8f4c2b1e-0d3a-4f7b-9c21-6e5a8b7d4f13",
      "comment_html": "<p>Deployed the fix to staging. Please re-test.</p>",
      "comment_stripped": "Deployed the fix to staging. Please re-test.",
      "access": "INTERNAL",
      "actor_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430",
      "external_id": null,
      "external_source": null,
      "edited_at": null,
      "created_at": "2026-01-14T09:22:41.478363Z",
      "created_by_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430"
    },
    {
      "id": "a2e04c77-3f19-4d5b-8a6e-91b0c7d2e845",
      "work_item_id": "8f4c2b1e-0d3a-4f7b-9c21-6e5a8b7d4f13",
      "comment_html": "<p>Re-tested on staging, the login flow is clean now.</p>",
      "comment_stripped": "Re-tested on staging, the login flow is clean now.",
      "access": "INTERNAL",
      "actor_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430",
      "external_id": "ZD-88412",
      "external_source": "zendesk",
      "edited_at": "2026-01-15T11:04:02.115740Z",
      "created_at": "2026-01-15T10:58:19.902314Z",
      "created_by_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430"
    }
  ],
  "next": null,
  "previous": null,
  "total_count": 2,
  "pagination": {
    "style": "offset"
  }
}
Response200
json
{
  "data": [
    {
      "id": "c1f7a3d9-2b64-4f80-9c1a-3d5e8b2a6c47",
      "work_item_id": "8f4c2b1e-0d3a-4f7b-9c21-6e5a8b7d4f13",
      "comment_html": "<p>Deployed the fix to staging. Please re-test.</p>",
      "comment_stripped": "Deployed the fix to staging. Please re-test.",
      "access": "INTERNAL",
      "actor_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430",
      "external_id": null,
      "external_source": null,
      "edited_at": null,
      "created_at": "2026-01-14T09:22:41.478363Z",
      "created_by_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430"
    }
  ],
  "next_cursor": "b3A9MTcxNDpjMWY3YTNkOQ",
  "has_more": true,
  "pagination": {
    "style": "cursor"
  }
}