List property options
Return the selectable choices of a single project-level property as a paginated list. Use it to build a picker for an OPTION property, or to resolve a 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 depend on the mode, 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. This endpoint has no search parameter.
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 presents its choices increated_at,-created_at: when each option was addedid,-id
Order by sort_order when you render the picker for a user. It matches the order in Plane's UI. You can order by created_at, but it isn't 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. Use the next value from the response instead of computing offsets yourself.
paginate:optionalstringSet to cursor to switch to the keyset envelope, which skips the COUNT query and returns next_cursor and has_more instead of next and total_count. Leave it out to get 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.

