List workspace work item properties
Return the workspace's custom property catalog as a paginated list. This is how you resolve a property name to the id you need when creating a context or attaching the property to a work item type, and how you build a picker that stays in sync with what the workspace has defined.
The list is the catalog, not what is live: it includes properties that have no context yet and therefore do not appear on any work item. Reads here are unaffected by the workspace's work item type mode.
Path Parameters
slug:requiredstringThe workspace slug. It appears in your Plane URLs — in https://app.plane.so/my-team/projects/, the slug is my-team.
Query Parameters
This list takes no filters or search term — the whole catalog is returned, page by page. Check your spelling on order_by and paginate: neither is validated, so an unrecognized order_by silently falls back to the default ordering and anything other than paginate=cursor silently uses offset pagination.
Ordering
order_by:optionalstringField to sort by. Prefix with - for descending.
sort_order,-sort_order— the display order Plane uses for the property list. This is the order you want when rendering a form; note thatsort_orderitself is not returned on the property object.created_at,-created_at— when each property was createdid,-id
Pagination
per_page:optionalintegerPage size. Defaults to 50, maximum 200.
offset:optionalintegerNumber 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:optionalstringSet to cursor to opt into the COUNT-free keyset envelope, which returns next_cursor and has_more instead of next and total_count. Omit it for the default offset envelope.
count:optionalbooleanDefaults to true. Set to false to skip the COUNT(*) behind total_count; the field is then omitted from the response.
Scopes
workspaces.work_item_properties:read
Errors
| Status | Code | Cause |
|---|---|---|
401 | unauthorized | Missing or invalid credentials. |
403 | forbidden | Your role or token scope can't read workspace work item properties. |
404 | resource_not_found | No such workspace, or it's outside your tenant. |
429 | rate_limited | Throttled. Honor the Retry-After header before retrying. |
curl -X GET \
"https://api.plane.so/api/v2/workspaces/my-team/work-item-properties/?order_by=sort_order&per_page=50" \
-H "X-Api-Key: $PLANE_API_KEY"import requests
response = requests.get(
"https://api.plane.so/api/v2/workspaces/my-team/work-item-properties/",
headers={"X-Api-Key": "your-api-key"},
params={"order_by": "sort_order", "per_page": 50},
)
print(response.json())const params = new URLSearchParams({ order_by: "sort_order", per_page: "50" });
const response = await fetch(`https://api.plane.so/api/v2/workspaces/my-team/work-item-properties/?${params}`, {
headers: {
"X-Api-Key": "your-api-key",
},
});
const data = await response.json();{
"data": [
{
"id": "a7e3f1d0-5c92-4b68-8f31-2d4a6b9e0c15",
"name": "severity",
"display_name": "Severity",
"description": "How badly the customer is affected",
"property_type": "OPTION",
"relation_type": null,
"is_required": true,
"is_multi": false,
"is_active": true,
"default_value": ["Major"],
"options": [
{
"id": "9d2c7b41-6a80-4f35-8e19-5c3b0a7d2e46",
"name": "Critical",
"description": "Production is down",
"is_default": false,
"sort_order": 10000,
"external_id": null,
"external_source": null
},
{
"id": "5a83e0b7-2c46-4d19-9f70-6b12c8e5a03d",
"name": "Major",
"description": "A core workflow is broken",
"is_default": true,
"sort_order": 20000,
"external_id": null,
"external_source": null
}
],
"settings": {},
"validation_rules": {},
"logo_props": {},
"external_id": null,
"external_source": null,
"created_at": "2026-01-14T09:22:41.478363Z"
},
{
"id": "c58b2e94-71a3-4d0f-9e62-4a1c7f38b5d2",
"name": "reviewer",
"display_name": "Reviewer",
"description": "Who signs off before release",
"property_type": "RELATION",
"relation_type": "USER",
"is_required": false,
"is_multi": true,
"is_active": true,
"default_value": [],
"options": [],
"settings": {},
"validation_rules": {},
"logo_props": {},
"external_id": null,
"external_source": null,
"created_at": "2026-01-14T09:23:12.904551Z"
},
{
"id": "3fb6c0d8-4e21-49a7-b5c3-90ad72e14f6b",
"name": "rollout_date",
"display_name": "Rollout date",
"description": "When the fix reaches customers",
"property_type": "DATETIME",
"relation_type": null,
"is_required": false,
"is_multi": false,
"is_active": true,
"default_value": [],
"options": [],
"settings": {},
"validation_rules": {},
"logo_props": {},
"external_id": null,
"external_source": null,
"created_at": "2026-01-14T09:24:03.112884Z"
}
],
"next": null,
"previous": null,
"total_count": 3,
"pagination": {
"style": "offset"
}
}{
"data": [
{
"id": "a7e3f1d0-5c92-4b68-8f31-2d4a6b9e0c15",
"name": "severity",
"display_name": "Severity",
"description": "How badly the customer is affected",
"property_type": "OPTION",
"relation_type": null,
"is_required": true,
"is_multi": false,
"is_active": true,
"default_value": ["Major"],
"options": [],
"settings": {},
"validation_rules": {},
"logo_props": {},
"external_id": null,
"external_source": null,
"created_at": "2026-01-14T09:22:41.478363Z"
}
],
"next_cursor": "b3A9MTcx",
"has_more": true,
"pagination": {
"style": "cursor"
}
}Match on id, not label
display_name is a label humans edit. Resolve it to id once and store the id — that is what contexts, type attachments, and property values refer to.

