Update a property context
Change what a context covers, what it imposes on the property inside that coverage, or both in one request. The scope fields change the boundary, and is_required, is_multi, default_value, settings, and options change the rules within it.
PATCH is partial at the field level. Send only the fields you want to change; anything you omit keeps its current value. Fields that hold collections behave differently. See Lists are replaced, not merged.
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.
property_id:requiredstring (uuid)The workspace-level property the context belongs to. A project-level property id is not addressable here and returns 404 not_found.
pk:requiredstring (uuid)The id of the context to update.
Body parameters
Every field is optional. Send only the fields you're changing. The scope is the one constraint that still applies to a partial update: neither axis may be left without coverage, so to turn a wildcard flag off, send the ids that replace it in the same request.
name:optionalstringNew display name, unique among this property's contexts. Maximum 255 characters.
applies_to_all_projects:optionalbooleanSwitch the project axis between "every project" and an explicit list.
Setting it to true discards the context's stored project_ids, so the context reads back with an empty list. Setting it to false requires project_ids in the same request unless the context already has projects stored.
Only one context per property may have this set to true, so turning it on while another context holds the slot returns 400.
project_ids:optionalarray of string (uuid)Replace the exact set of projects this context covers. What you send becomes the whole list: ids you leave out are unlinked, and ids you add are linked.
Rejected with a 400 when applies_to_all_projects is true, and when the list would be empty while the flag is false. Every id must belong to this workspace, and duplicates are rejected. Write-only as an input; the response echoes the stored links in project_ids.
applies_to_all_work_item_types:optionalbooleanSwitch the work item type axis between "every type" and an explicit list. Same rules as applies_to_all_projects: turning it on clears issue_type_ids, and turning it off requires types to fall back on.
issue_type_ids:optionalarray of string (uuid)Replace the exact set of work item types this context covers. Same set-replacement semantics as project_ids, and the same validation against the wildcard flag.
is_required:optionalbooleanWhether the property must be filled in inside this scope. Replaces the property's own is_required here.
is_multi:optionalbooleanWhether the property accepts several values inside this scope. Replaces the property's own is_multi here.
default_value:optionalarray of stringValues applied when a work item in this scope has nothing set. For OPTION properties, options in this context flagged is_default take precedence over this array.
options:optionalarray of objectReplace this context's option list. Entries are the same shape as on create: id to keep an existing option, name to add a new one, plus optional description and is_default. An option's sort_order is read-only. Plane assigns it from the order of the entries you send.
Sending this field rewrites the list. Any option currently on the context that you do not reference by id is removed, along with the values recorded through it. To keep an option and change nothing about it, include { "id": "…" }.
settings:optionalanyType-specific configuration for this scope, as a JSON object. Replaces the property's own settings here.
sort_order:optionalnumberOrdering weight among this property's contexts. Lower values sort first. It's only for display and doesn't affect which context wins for a work item.
external_id:optionalstringYour system's identifier for this context. Maximum 255 characters. Must be sent together with external_source, and the pair must be unique within the property.
external_source:optionalstringThe system external_id came from, for example github or jira. Maximum 255 characters. Must be sent together with external_id.
Response shaping
fields:optionalstringComma-separated list of fields to return. Fields you don't request are left out of the response instead of coming back as null, so a missing key means you didn't ask for it and null means the value is null. id is always included, whether or not you name it.
Pass all to get every requestable field. An unknown field name returns 400 with the list of valid names and the closest match, so a typo is caught instead of being silently ignored.
Requestable here: applies_to_all_projects, applies_to_all_work_item_types, created_at, default_value, external_id, external_source, id, is_default, is_multi, is_required, issue_type_ids, name, options, project_ids, settings, sort_order, updated_at, updated_by_id.
See Sparse fields.
Scopes
workspaces.work_item_properties:write
Errors
| Status | Code | Cause |
|---|---|---|
400 | invalid_request | An axis left without coverage, a list sent alongside its wildcard flag, an id outside the workspace, a duplicate name, a half-filled external pair, or an overlap with a same-tier context. |
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 change workspace property settings. |
404 | not_found | No such context, property, or workspace, or it's outside your tenant. |
406 | not_acceptable | The Accept header asks for a representation the API can't produce. |
409 | conflict | This workspace manages work item types per project, so workspace-level property writes are refused. |
413 | payload_too_large | The request body is over the size limit. |
415 | unsupported_media_type | The Content-Type isn't one this endpoint accepts. |
429 | rate_limited | Throttled. Honor the Retry-After header before retrying. |
A context can never cover nothing
{"applies_to_all_projects": false} on its own returns 400 when the context has no stored projects, and so does {"project_ids": []}. An empty scope would strand every value recorded under this context, so Plane refuses the write instead. Send the flag and the replacement ids together.
Workspace mode only
Updating a context requires the workspace to manage work item types at the workspace level. In project mode the request returns 409 work_item_types_managed_at_project. Reads are unaffected. See Work item type modes.
curl -X PATCH \
"https://api.plane.so/api/v2/workspaces/my-team/work-item-properties/d1f7a3c9-5b62-4e08-9a41-7c3e2f8b6d05/contexts/6e2b90d4-1c73-4f58-a09e-3d8b5c14e7f2/" \
-H "X-Api-Key: $PLANE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Bug and incident severity",
"issue_type_ids": [
"b7e04a95-2f18-4c63-9d57-8a12e6b0f439",
"3a5c81d7-9e26-4b04-a17f-5c8d2e930b61"
]
}'import requests
response = requests.patch(
"https://api.plane.so/api/v2/workspaces/my-team/work-item-properties/d1f7a3c9-5b62-4e08-9a41-7c3e2f8b6d05/contexts/6e2b90d4-1c73-4f58-a09e-3d8b5c14e7f2/",
headers={"X-Api-Key": "your-api-key"},
json={
"name": "Bug and incident severity",
"issue_type_ids": [
"b7e04a95-2f18-4c63-9d57-8a12e6b0f439",
"3a5c81d7-9e26-4b04-a17f-5c8d2e930b61",
],
},
)
print(response.json())const response = await fetch(
"https://api.plane.so/api/v2/workspaces/my-team/work-item-properties/d1f7a3c9-5b62-4e08-9a41-7c3e2f8b6d05/contexts/6e2b90d4-1c73-4f58-a09e-3d8b5c14e7f2/",
{
method: "PATCH",
headers: {
"X-Api-Key": "your-api-key",
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Bug and incident severity",
issue_type_ids: [
"b7e04a95-2f18-4c63-9d57-8a12e6b0f439",
"3a5c81d7-9e26-4b04-a17f-5c8d2e930b61",
],
}),
},
);
const data = await response.json();{
"id": "6e2b90d4-1c73-4f58-a09e-3d8b5c14e7f2",
"name": "Bug and incident severity",
"is_required": true,
"is_multi": false,
"is_default": false,
"default_value": [],
"settings": {},
"sort_order": 75535,
"applies_to_all_projects": false,
"applies_to_all_work_item_types": false,
"external_id": null,
"external_source": null,
"created_at": "2026-02-03T11:05:17.204918Z",
"updated_at": "2026-02-03T16:45:12.904117Z",
"updated_by_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430",
"project_ids": ["4af68566-94a4-4eb3-94aa-50dc9427067b", "9c3d7e21-6b45-4a80-8f19-2e0c7b5d3a64"],
"issue_type_ids": [
"b7e04a95-2f18-4c63-9d57-8a12e6b0f439",
"3a5c81d7-9e26-4b04-a17f-5c8d2e930b61"
],
"options": [
{
"id": "c58e2f01-4d97-4b3a-8e26-1f0b7a9c5d34",
"name": "S1 — Critical",
"is_default": false,
"sort_order": 10000
},
{
"id": "a49b6c72-8e15-4d30-b57c-2f81e0a6d938",
"name": "S2 — Major",
"is_default": true,
"sort_order": 20000
},
{
"id": "f13c8a60-7d24-4e59-9b02-6a5f1c3e8d47",
"name": "S3 — Minor",
"is_default": false,
"sort_order": 30000
}
]
}{
"type": "invalid_request",
"code": "invalid_request",
"detail": "The request body failed validation.",
"errors": [
{
"field": "project_ids",
"code": "invalid",
"message": "Ignored when applies_to_all_projects is true; omit it."
}
]
}Lists are replaced, not merged
project_ids, issue_type_ids, and options are set-replacements. What you send replaces the whole collection instead of adding to it:
- If you omit the field, the collection stays as it was. This is the safe default, and it's why the request above changed the type axis without touching projects or options.
- If you send the field, what you send becomes the collection. Ids you leave out are unlinked. For
options, an option you leave out is deleted along with the values recorded through it.
To add one project to a context, read the current project_ids, append to it, and send the full list back. To keep an option unchanged while editing its siblings, include it as { "id": "…" }.
Moving between a list and the wildcard
The flag and the list are alternatives on each axis. To switch between them:
- From a list to the wildcard, send
{"applies_to_all_projects": true}and nothing else on that axis. Sendingproject_idsin the same request returns400. Plane drops the stored project links, so the context reads back with"project_ids": [], which now means every project. - From the wildcard to a list, send
{"applies_to_all_projects": false, "project_ids": ["…"]}in one request. The flag alone returns400when the context has no stored projects to fall back on.
The work item type axis follows the same two rules with applies_to_all_work_item_types and issue_type_ids.
Changing scope can delete recorded values
Every scope edit re-resolves which context each work item uses, and Plane removes values that are left without a valid context:
- A work item whose project and type are no longer covered by any context on this property loses its value for that property.
- If a work item is still covered but its option value belongs to a context that no longer resolves there, that value is dropped too, because Plane offers only the resolved context's option list.
Narrowing a context triggers this, and so does widening one so it outranks another with a different option list. Read the property's full context list before you change a boundary, and treat a scope edit as a migration.
Overrides apply wherever this context resolves
is_required, is_multi, default_value, settings, and options take effect as soon as the request succeeds, on every work item that resolves to this context. They replace the property's own values there rather than combining with them, so editing the property itself will not change behavior in a scope that a context already covers.
Which work items those are depends on the other contexts on the property, because a more specific context still outranks this one. See Property contexts overview for the precedence rules, and List property contexts to see them all at once.

