List property options
Return the selectable choices of a single project-level property as a paginated list. This is how you build a picker for an OPTION property, and how you resolve a human-readable label such as Critical to the option id you must send when setting a property value on a work item.
The property in the path must have property_type: "OPTION" — see Work item properties. Properties of any other type have no options.
Reads work in either work item type mode — only writes are mode-gated, so listing options never returns 409. See Work item type modes.
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.
project_id:requiredstring (uuid)The project that owns the property.
property_id:requiredstring (uuid)The property whose options you want to list. A property id from another project returns 404, even inside the same workspace.
Query Parameters
Filters combine with AND. There is no search.
name:optionalstringReturn options with this name, compared case-insensitively. ?name=critical matches Critical, so you can resolve a label to its option id without reading the whole list.
external_id:optionalstringReturn options whose external_id matches exactly. Use it to find the option you created earlier for a value in another system.
external_source:optionalstringReturn options from one source system, for example jira. Combine it with external_id, because an external_id is unique only within its source.
Check your spelling on order_by. A value outside the list below isn't rejected. It falls back to the default ordering, so a typo shows up as an unexpected sort order rather than an error.
Ordering
order_by:optionalstringField to sort by. Prefix with - for descending.
sort_order,-sort_order— the order the property itself presents its choices increated_at,-created_at— when each option was addedid,-id
Order by sort_order when you are rendering the picker to a user; it matches what Plane's own UI shows. created_at is orderable but is not returned in the response body.
Pagination
per_page:optionalintegerPage size. Defaults to 50, maximum 200. Most properties have well under 50 options, so one page is usually the entire list.
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
projects.work_item_properties:read
Errors
| Status | Code | Cause |
|---|---|---|
401 | unauthorized | Missing or invalid credentials. |
402 | payment_required | The feature this endpoint belongs to isn't enabled on your plan, or is switched off. |
403 | forbidden | Your role or token scope can't read this project's properties. |
404 | not_found | No such property, project, or workspace — or the property belongs to a different project. |
406 | not_acceptable | The Accept header asks for a representation the API can't produce. |
429 | rate_limited | Throttled. Honor the Retry-After header before retrying. |
No expansion on options
Property options don't accept ?expand=. The response is the flat option object shown here.
curl -X GET \
"https://api.plane.so/api/v2/workspaces/my-team/projects/4af68566-94a4-4eb3-94aa-50dc9427067b/work-item-properties/c1a7f2d8-6b34-4e59-9f80-2d4a7c31e6b5/options/?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/projects/4af68566-94a4-4eb3-94aa-50dc9427067b/work-item-properties/c1a7f2d8-6b34-4e59-9f80-2d4a7c31e6b5/options/",
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/projects/4af68566-94a4-4eb3-94aa-50dc9427067b/work-item-properties/c1a7f2d8-6b34-4e59-9f80-2d4a7c31e6b5/options/?${params}`,
{
headers: {
"X-Api-Key": "your-api-key",
},
},
);
const data = await response.json();{
"data": [
{
"id": "9d3b5c71-2e48-4a6f-b1c9-7f0e83d25a64",
"name": "Critical",
"description": "Customer-visible outage",
"parent_id": null,
"is_default": false,
"is_active": true,
"sort_order": 15000,
"logo_props": {},
"external_id": null,
"external_source": null,
"updated_at": "2026-01-14T09:22:41.478363Z",
"updated_by_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430"
},
{
"id": "5e2a0c93-7d41-4b8e-a36f-91c4d0b7e582",
"name": "Major",
"description": "Degraded but usable",
"parent_id": null,
"is_default": true,
"is_active": true,
"sort_order": 25000,
"logo_props": {},
"external_id": null,
"external_source": null,
"updated_at": "2026-01-14T09:22:41.478363Z",
"updated_by_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430"
},
{
"id": "a84f1b60-95c2-4d37-8e5a-3b0f6d29c471",
"name": "Minor",
"description": "Cosmetic or low impact",
"parent_id": null,
"is_default": false,
"is_active": true,
"sort_order": 35000,
"logo_props": {},
"external_id": null,
"external_source": null,
"updated_at": "2026-01-14T09:22:41.478363Z",
"updated_by_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430"
}
],
"next": null,
"previous": null,
"total_count": 3,
"pagination": {
"style": "offset"
}
}{
"data": [
{
"id": "9d3b5c71-2e48-4a6f-b1c9-7f0e83d25a64",
"name": "Critical",
"description": "Customer-visible outage",
"parent_id": null,
"is_default": false,
"is_active": true,
"sort_order": 15000,
"logo_props": {},
"external_id": null,
"external_source": null,
"updated_at": "2026-01-14T09:22:41.478363Z",
"updated_by_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430"
}
],
"next_cursor": "b3A9MTcx",
"has_more": true,
"pagination": {
"style": "cursor"
}
}Cache the id, refresh the label
The option id is what a work item stores. Cache the id-to-name mapping from this endpoint and refresh it when you render, so a rename in Plane shows up in your UI without breaking the values you already wrote.

