Skip to content

List type properties

GET/api/v2/workspaces/{slug}/projects/{project_id}/work-item-types/{type_id}/properties/

Return the custom properties currently attached to one work item type, as a paginated list. This is the call that answers "what fields does a Bug have?" — reach for it before rendering a form, validating an import, or deciding which property values to send when you create a work item.

Each entry is the full property definition, not a link stub, so labels, input types, and option lists all arrive in this one response. Properties that exist in the project but are not attached to this type are not returned; for the project-wide inventory use List work item properties.

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 type belongs to.

type_id:requiredstring (uuid)

The work item type whose properties you want to list.

Query Parameters

There are no filters on this endpoint — the attachment itself is the filter. What you can control is ordering and page size.

Neither order_by nor paginate is validated — check your spelling, because both fail silently. A value outside the lists below is not rejected: an unrecognized order_by falls back to the default ordering, and anything other than paginate=cursor uses offset pagination.

Ordering

order_by:optionalstring

Field to sort by. Prefix with - for descending.

  • sort_order , -sort_order — the order the properties are shown in, and the default
  • created_at , -created_at — when each property was created
  • id , -id

Order by sort_order when you are rendering the type's form to a user; it is the order Plane itself uses. Note that sort_order is not part of the returned property object — sort by created_at or id if you need the sort key to be visible in the payload.

Pagination

per_page:optionalinteger

Page size. Defaults to 50, maximum 200. Most types carry a handful of properties, so one page is usually the whole set.

offset:optionalinteger

Number of rows to skip from the start of the result set. Maximum 10000. Read the next value from the response rather than computing offsets yourself.

paginate:optionalstring

Set to cursor to opt into the COUNT-free keyset envelope, which returns next_cursor and has_more instead of next and total_count. Pair it with order_by=created_at or order_by=id — the default sort_order is not a unique key, so it is not cursor-eligible. Omit the parameter for the default offset envelope.

count:optionalboolean

Defaults to true. Set to false to skip the COUNT(*) behind total_count; the field is then omitted from the response.

Scopes

projects.work_item_types:read

Errors

StatusCodeCause
401unauthorizedMissing or invalid credentials.
403forbiddenYour role or token scope can't read this project's work item types.
404resource_not_foundNo such workspace, project, or type — or it's outside your tenant.
429rate_limitedThrottled. Honor the Retry-After header before retrying.

Reads work in either mode

Listing is not mode-gated. A project surfaces the properties on its types whether the workspace manages types at the project level or the workspace level — only the writes on this path (attach and detach) care. See Work item type modes.

List type properties
bash
curl -X GET \
  "https://api.plane.so/api/v2/workspaces/my-team/projects/4af68566-94a4-4eb3-94aa-50dc9427067b/work-item-types/9d3c7f21-6b48-4e0a-8f52-2c1d7a904e66/properties/?order_by=sort_order&per_page=50" \
  -H "X-Api-Key: $PLANE_API_KEY"
Response200
json
{
  "data": [
    {
      "id": "c1f0a2d4-73b9-4e6c-8a15-9d0e4b3f7c28",
      "name": "severity",
      "display_name": "Severity",
      "description": "How badly this bug affects users",
      "property_type": "OPTION",
      "relation_type": null,
      "is_required": true,
      "is_multi": false,
      "is_active": true,
      "default_value": [],
      "settings": {},
      "validation_rules": {},
      "logo_props": {},
      "external_id": null,
      "external_source": null,
      "created_at": "2026-01-14T09:22:41.478363Z",
      "options": [
        {
          "id": "3b6f1c88-0d24-4a97-9f53-71e8c2b4a069",
          "name": "Critical",
          "description": "Data loss or full outage",
          "is_default": false,
          "sort_order": 10000,
          "external_id": null,
          "external_source": null
        },
        {
          "id": "7e2a9046-5c31-4d8b-a4f6-0b95e13d72c8",
          "name": "Major",
          "description": "Core workflow blocked",
          "is_default": true,
          "sort_order": 20000,
          "external_id": null,
          "external_source": null
        }
      ]
    },
    {
      "id": "5e8b3417-2a6d-4c91-b0f7-8d2e14a6c395",
      "name": "root-cause",
      "display_name": "Root cause",
      "description": "What actually broke",
      "property_type": "TEXT",
      "relation_type": null,
      "is_required": false,
      "is_multi": false,
      "is_active": true,
      "default_value": [],
      "settings": {},
      "validation_rules": {},
      "logo_props": {},
      "external_id": null,
      "external_source": null,
      "created_at": "2026-01-14T09:24:03.201884Z",
      "options": []
    }
  ],
  "next": null,
  "previous": null,
  "total_count": 2,
  "pagination": {
    "style": "offset"
  }
}
Response200
json
{
  "data": [
    {
      "id": "5e8b3417-2a6d-4c91-b0f7-8d2e14a6c395",
      "name": "root-cause",
      "display_name": "Root cause",
      "description": "What actually broke",
      "property_type": "TEXT",
      "relation_type": null,
      "is_required": false,
      "is_multi": false,
      "is_active": true,
      "default_value": [],
      "settings": {},
      "validation_rules": {},
      "logo_props": {},
      "external_id": null,
      "external_source": null,
      "created_at": "2026-01-14T09:24:03.201884Z",
      "options": []
    }
  ],
  "next_cursor": "b3A9MTcx",
  "has_more": true,
  "pagination": {
    "style": "cursor"
  }
}

Branch on property_type, not on the label

display_name is what a human renamed the field to this week. property_type, is_multi, and is_required are what tell your code whether to render a date picker or a multi-select and whether a value is mandatory. Key your integration on id and property_type; treat display_name as text for humans.