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 invalid_request, 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.

Response shaping ​

fields:optionalstring

Comma-separated list of fields to return on each row. Unrequested keys are omitted from the response, not returned as null, so absent means "not requested" and null means "actually null". id always comes back whether or not you name it.

Pass all for every requestable field. An unknown name is a 400 that lists the valid set and suggests the closest match, so a typo can't silently cost you the saving.

Requestable here: access, actor_id, comment_html, comment_stripped, created_at, created_by_id, edited_at, external_id, external_source, id, work_item_id.

See Sparse fields.

expand:optionalstring

Comma-separated relations to embed alongside the ids: actor (the comment author).

Expansion is separate-key: ?expand=state keeps state_id and adds a state object next to it, so an id is never replaced by an object. An unknown value is a 400.

?fields= and ?expand= are independent namespaces. Relation names are not valid ?fields= tokens (and vice versa), and an expanded object survives field filtering — ?fields=id,name&expand=state returns id, name and state. See Expanding relations.

Scopes ​

projects.work_items.comments:read

Errors ​

StatusCodeCause
401unauthorizedMissing or invalid credentials.
402payment_requiredThe feature this endpoint belongs to isn't enabled on your plan, or is switched off.
403forbiddenYour role or token scope can't read this work item.
404not_foundNo such workspace, project, or work item, or it's outside your tenant.
406not_acceptableThe Accept header asks for a representation the API can't produce.
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"
  }
}